Automatically save PDFs on iOS

This guide covers advanced topics related to automatically saving changes to documents. In most cases, you should instead read our introductory guide on autosaving, which covers the events that trigger autosaving.

The default autosave mechanism works well, but there’s still the possibility of losing data if a device restarts or runs out of battery, or if your application crashes before a save completes.

Nutrient offers document checkpointing as a crash recovery mechanism to restore unsaved changes. This is an advanced feature that’s disabled by default, as it requires some configuration to work effectively.

Warning: There are currently issues with document checkpointing that may cause the app to freeze. We don’t recommend using this feature for now.

Nutrient Instant stores annotations in a database and synchronizes with Document Engine as soon as a connection is available, which greatly reduces the chances of data loss if the app terminates suddenly. No checkpointing or other custom setup is needed. Read more in our Instant offline support guide.

Understanding document checkpoints

A checkpoint contains all the unsaved data in a document. For the sake of this explanation, this is the “dirty” data. This data is temporary and persisted into the document when Document.save(options:) is called. With document checkpoints, this dirty data can be continually saved to a separate checkpoint file, and in the event of a crash, it can be restored to the document.

Nutrient allows you to control when these checkpoints are saved. This is done by setting DocumentCheckpointer.strategy on the checkpointer property available on each Document.

The following strategies are available:

For most use cases, .immediate is a good option and doesn’t affect performance by any significant amount.

Loading a saved checkpoint

To load a previously saved checkpoint, use the appropriate Document initializer — Document(url:loadCheckpointIfAvailable:) or Document(dataProviders:loadCheckpointIfAvailable:).

Passing in YES to the loadCheckpointIfAvailable parameter loads the checkpoint, if it’s available. Note that while the document will contain any previously unsaved objects saved in the checkpoint, the loaded changes aren’t saved to the document. To do this, you must still call Document.save(options:). This will cause the data from the checkpoint file to be written into the document, after which point the checkpoint will be deleted from disk by the DocumentCheckpointer.

Additional information

Supported document types

Documents are backed by more than one provider aren’t currently supported by document checkpoints. Documents that aren’t backed by a file (Data/custom data provider) work well checkpointing, as long as certain care is taken with regard to their UID. When enabling checkpointing on a document that uses a custom UID, one must be sure the UID is unique to that document, since the DocumentCheckpointer uses the UID as a part of the checkpoint’s file name. Opening multiple instances of a document with the same UID and making changes to them while they have checkpointing enabled isn’t supported and will result in undefined behavior.

Checkpoint location

The checkpoints are stored in a subdirectory in the Library directory (more information) folder. You don’t have to manage this manually, since each DocumentCheckpointer will always delete the document’s previous checkpoint before saving the new one. Additionally, the directory in which the checkpoints are stored is cleaned up by removing any checkpoints older than a week. The checkpoints aren’t shared between the main app executable and any of its app extensions, since the Library directory is unique to each of them. Therefore, if an extension crashes while a document has unsaved changes, those changes won’t be recoverable from the app or another extension.

Performance

There are two things to consider with document checkpointing in terms of performance:

  • Saving — Depending on the strategy, the DocumentCheckpointer saves checkpoints to the location specified above on a low priority background queue. This shouldn’t affect your application’s performance in any meaningful way.

  • Loading — When loading the checkpoints as specified above, the loading of a document may take a little longer than usual, since that’s when the document is parsed, but the initializers of Document aren’t affected. Since Document only parses the document when it’s actually required, you might see a small slowdown when accessing properties that require parsing.