The UIDocument class is an abstract base class for managing the data of documents.


Applications that make use of UIDocument and its underlying architecture get many benefits for their documents:

  • Asynchronous reading and writing of data on a background queue. Your application's responsiveness to users is thus unaffected while reading and writing operations are taking place.

  • Coordinated reading and writing of document files that is automatically integrated with cloud services.

  • Support for discovering conflicts between different versions of a document (if that occurs).

  • Safe-saving of document data by writing data first to a temporary file and then replacing the current document file with it.

  • Automatic saving of document data at opportune moments; this mechanism includes support for dealing with suspend behaviors.

In the Model-View-Controller design pattern, a UIDocument object is a model object or model-controller object—it manages the data of a document or the aggregate model objects that together constitute the document's data. You typically pair it with a view controller that manages the view presenting the document’s contents. UIDocument provides no support for managing document views.

Document-based applications include those that can generate multiple documents, each with its own file-system location. A document-based application must create a subclass of UIDocument for its documents. See “Subclassing Notes,” below, for details.

The primary attribute of a document in the UIDocument architecture is its file URL. When you initialize an instance of your document subclass by calling init(fileURL:), you must pass a file URL locating the document file in the application sandbox. UIDocument determines the file type (the Uniform Type Identifier associated with the file extension) and the document name (the filename component) from the file URL. You can override the accessor methods of the fileType and localizedName properties to supply different values.

The following outlines the life cycle of a typical document (see “Subclassing Notes” for implementation details):

  1. You create a new document or open an existing document.

    • To create a new document, allocate and initialize an instance of your subclass and then call save(to:for:completionHandler:) on the instance.

    • To open an existing document (selected by the user), allocate and initialize an instance of your subclass and then call open(completionHandler:) on the instance.

  2. The user edits the document.

    As the user edits, track changes to the document. UIDocument periodically notes when there are unsaved changes and writes the document data to its file.

  3. The user requests that the document to be integrated with cloud services (optional).

    You must enable the document for cloud storage. You must also resolve any conflicts between different versions of the same document.

  4. The user closes the document.

    Call close(completionHandler:) on the document instance. UIDocument saves the document if there are any unsaved changes.

A typical document-based application calls open(completionHandler:), close(completionHandler:), and save(to:for:completionHandler:) on the main thread. When the read or save operation kicked off by these methods concludes, the completion-handler block is executed on the same dispatch queue on which the method was invoked, allowing you to complete any tasks contingent on the read or save operation. If the operation is not successful, false is passed into the completion-hander block.

Implementation of the NSFilePresenter Protocol

The UIDocument class adopts the NSFilePresenter protocol. When another client attempts to read the document of a UIDocument-based application, that reading is suspended until the UIDocument object is given an opportunity to save any changes made to the document.

Although some implementations do nothing, UIDocument implements all NSFilePresenter methods, . Specifically, UIDocument:

In your UIDocument subclass, if you override a NSFilePresenter method you can always invoke the superclass implementation (super).

Subclassing Notes

Each document-based application must create a subclass of UIDocument whose instances represent its documents. The subclassing requirements for most applications are simple:

  • For writing operations, implement the contents(forType:) method to provide a snapshot of document data. The data must be in the form of an NSData object (for flat files) or an FileWrapper object (for file packages). Writing operations are usually initiated through the autosave feature

  • For reading operations, implement the load(fromContents:ofType:) method to receives an NSData or FileWrapper object and initialize the application's data structures with it.

  • Implement change tracking to enable the autosaving feature. See Change Tracking for details.

  • When cloud services are enabled for a document, resolve conflicts between different versions of a document. See Conflict Resolution and Error Handling for details.

The contents(forType:) and load(fromContents:ofType:) methods are typically called on the main queue. More specifically:

  • The contents(forType:) method is called on the queue that the save(to:for:completionHandler:) method was called on; writing of data takes place on a background thread

  • The load(fromContents:ofType:) method is called on the queue that the open(completionHandler:) method was called on

If you have special requirements for reading and writing document data for which the contents(forType:) and load(fromContents:ofType:) methods won’t suffice, you can override other methods of the UIDocument class. See Advanced Overrides for a discussion of these requirements and methods.

Change Tracking

To enable the autosaving feature of UIDocument, you must notify it when users make changes to a document. UIDocument periodically checks whether the hasUnsavedChanges method returns true; if it does, it initiates the save operation for the document.

There are two primary ways to implement change tracking in your UIDocument subclass:

  • Call the methods of the UndoManager class to implement undo and redo for the document. You can access the default UndoManager object from the undoManager property. This is the preferred approach, especially for existing applications that already support undo and redo.

  • Call the updateChangeCount(_:) method at the appropriate junctures in your code.

Conflict Resolution and Error Handling

A UIDocument object has a specific state at any moment in its life cycle. You can check the current state by querying the documentState property, and get notified about changes by observing the UIDocumentStateChanged notification.

If a document is enabled for iCloud, it is important to check for conflicting versions and to attempt to resolve conflicts. Do this by listening for the UIDocumentStateChanged notification and then checking if the document state is inConflict. This state indicates that there are conflicting versions of the document, which you can access by calling the NSFileVersion class method unresolvedConflictVersionsOfItem(at:), passing in the document’s file URL. If you can resolve a conflict correctly without user interaction, do so. Otherwise, discretely notify the user that a conflict exists and let them choose how to resolve it. Possible approaches include:

  • Displaying the conflicting versions, from which a user can pick one or both versions to keep

  • Displaying a merged version and giving the user an option to pick it

  • Displaying the file modification dates and giving the user the option to choose one or both

Document state, in addition to indicating an inter-file conflict, can indicate errors. For example, closed indicates an error in reading, and savingError indicates an error in saving or reverting a document. Your app is notified of reading and writing errors through the success parameter passed into the completion handlers of the open(completionHandler:), close(completionHandler:), revert(toContentsOf:completionHandler:), and save(to:for:completionHandler:) methods.

You can handle errors by calling or implementing the handleError(_:userInteractionPermitted:) method; this method is called by the default implementations of the open(completionHandler:) and save(to:for:completionHandler:) methods when a UIDocument object encounters a reading or writing error, respectively. You can handle read, save, and reversion errors by informing the user and, if the situation permits, trying to recover from the error.

Be sure to read the description for the contents(forType:) method for its guidance on handling errors encountered during document saving.

Advanced Overrides

If you application has special requirements for reading or writing document data, it can override methods of UIDocument other than load(fromContents:ofType:) and contents(forType:). These requirements often include the following:

If you override most of these methods be aware that all reading and writing of document data must be done on a background queue and must be coordinated with other attempts to read from and write to the same document file. Because of this, you should usually call the superclass implementation (super) as part of your override, and if you call other UIDocument methods you should usually invoke them in the block passed into a call of the performAsynchronousFileAccess(_:) method. Read the method descriptions for the details.

Thread Safety Considerations

If you override any of the document-attribute properties (listed under Accessing Document Attributes) by overriding the related accessor methods, be aware that the UIKit framework can call these accessor methods on a background thread. Thus your overriding implementation must be thread safe.


Initializing a Document Object

init(fileURL: URL)

Returns a document object initialized with its file-system location.

Accessing Document Attributes

var fileURL: URL

The file URL with which the document was initialized.

var localizedName: String

The localized name of the document.

var fileType: String?

The file type of the document.

var fileModificationDate: Date?

The date and time the document file was last modified.

var documentState: UIDocumentState

Returns the current state of the document.

Writing Document Data

func close(completionHandler: ((Bool) -> Void)? = nil)

Asynchronously closes the document after saving any changes.

func contents(forType: String)

Override this method to return the document data to be saved.

func save(to: URL, for: UIDocumentSaveOperation, completionHandler: ((Bool) -> Void)? = nil)

Saves document data to the specified location in the application sandbox.

func writeContents(Any, andAttributes: [AnyHashable : Any]? = nil, safelyTo: URL, for: UIDocumentSaveOperation)

Ensures that document data is written safely to a specified location in the application sandbox.

func writeContents(Any, to: URL, for: UIDocumentSaveOperation, originalContentsURL: URL?)

Writes the document data to disk at the sandbox location indicated by a file URL.

var savingFileType: String?

Returns the file type to use for saving a document.

func fileAttributesToWrite(to: URL, for: UIDocumentSaveOperation)

Returns a dictionary of file attributes to associate with the document file when writing or updating it.

func fileNameExtension(forType: String?, saveOperation: UIDocumentSaveOperation)

Returns a file extension to append to the file URL of the document file being written.

Reading Document Data

func load(fromContents: Any, ofType: String?)

Override this method to load the document data into the app’s data model.

func read(from: URL)

Reads the document data in a file at a specified location in the application sandbox.

Accessing Document Files Asynchronously

func performAsynchronousFileAccess(: @escaping () -> Void)

Schedules a document-reading or document-writing operation on a concurrent background queue.

Reverting a Document

func revert(toContentsOf: URL, completionHandler: ((Bool) -> Void)? = nil)

Reverts a document to the most recent document data stored on-disk.

Disabling and Enabling Editing

func disableEditing()

Overridden to disable editing when it is unsafe to make changes to a document.

func enableEditing()

Overridden to enable editing when it is safe again to make changes to a document.

Tracking Changes and Autosaving

var hasUnsavedChanges: Bool

Returns whether the document has any unsaved changes.

func updateChangeCount(UIDocumentChangeKind)

Update the change counter by indicating the kind of change.

var undoManager: UndoManager!

The undo manager for the document.

func changeCountToken(for: UIDocumentSaveOperation)

Overridden to return a change token for a specific save operation.

func updateChangeCount(withToken: Any, for: UIDocumentSaveOperation)

Overridden to update the change count with reference to a change-count token passed in by UIKit.

func autosave(completionHandler: ((Bool) -> Void)? = nil)

Called by UIKit to initiate automatic saving of documents with unsaved changes.

Supporting User Activities

var userActivity: NSUserActivity?

An object encapsulating a user activity supported by this document.

func restoreUserActivityState(NSUserActivity)

Restores the state needed to continue the given user activity.

func updateUserActivityState(NSUserActivity)

Updates the state of the given user activity.

Resolving Conflicts and Handling Errors

func handleError(Error, userInteractionPermitted: Bool)

Called or overridden to handle an error that occurs during an attempt to read, save, or revert a document.

func finishedHandlingError(Error, recovered: Bool)

Tells UIKit that you have finished handled the error.

func userInteractionNoLongerPermitted(forError: Error)

Sent when it is no longer safe to proceed without immediately handling the error.


Document URL User Activity Key

Key identifying the document associated with a user activity.


static let UIDocumentStateChanged: NSNotification.Name

Posted by the document object when there is a change in the state of the document.

Instance Properties