PSPDFInstantDocumentDescriptor

Objective-C

@protocol PSPDFInstantDocumentDescriptor <NSObject>

Swift

protocol InstantDocumentDescriptor : NSObjectProtocol

A PSPDFInstantDocumentDescriptor represents an editing context for annotations on a PDF file managed by Instant.

The document descriptor allows you to download the file and synchronize the annotations in this context, while display and editing of the annotations happens via the specialized Document objects that it provides. You obtain instances that conform to this protocol from a PSPDFInstantClient, which also keeps the instances it creates alive.

Instant manages the PDF files on disk efficiently, and will reuse the same file for all document descriptors with the same identifier. Therefore, there are some limitations to what you can do with the Document instances you obtain from a document descriptor. For details, see the documentation of editableDocument.

Notifications

A document descriptor posts the following notifications to inform you of relevant events:

Each of these notifications will typically be posted on a background thread, and have the document descriptor as their object property. For a centralized, more type-safe alternative see PSPDFInstantClientDelegate, and for more details on the sync cycle, refer to the documentation of PSPDFInstantDocumentState.

  • Uniquely identifies the PDF file backing this editing context.

    There can be multiple document descriptors that share the same PDF file and therefore the same identifier. To uniquely identify a document descriptor, you have to take the layerName into account as well.

    Declaration

    Objective-C

    @property (nonatomic, readonly) NSString *_Nonnull identifier;

    Swift

    var identifier: String { get }
  • Name of the layer that specifies the annotations to use for this editing context.

    The name of the default layer is an empty string.

    Declaration

    Objective-C

    @property (nonatomic, readonly) NSString *_Nonnull layerName;

    Swift

    var layerName: String { get }
  • The identifier of the user owning this object, as specified in the user_id claim of the JWTs used for syncing.

    PSPDFKit Server supports downloading and even syncing of layers without a value for the optional user_id claim in the JWT. This allows things like implementing a fully anonymous guest mode and skipping user management during the evaluation phase. To support upgrading anonymous users without loss of data, the value of this property can be changed exactly once from nil (no value at all) to a nonnull value through reauthentication with a new JWT that includes the userd_id claim. If reauthentication is successful, this property will be updated to reflect the change. The local data will be tied to this identifier. Any attempt to access or reauthenticate the document descriptor with a JWT containing a different user_id (or no such claim at all) will fail immediately.

    This property will be nil when your JWTs do not contain the user_id claim. It may also be nil, IFF you have downloaded the data with a version of Instant prior to the one bundled with PSPDFKit 7.6, and have not updated its JWT yet.

    Declaration

    Objective-C

    @property (nonatomic, readonly, nullable) NSString *userID;

    Swift

    var userID: String? { get }
  • A Boolean value indicating whether the PDF file for this document descriptor has been downloaded from the server.

    Declaration

    Objective-C

    @property (nonatomic, readonly, getter=isDownloaded) BOOL downloaded;

    Swift

    var isDownloaded: Bool { get }
  • The current state of the document descriptor.

    Warning

    This property is not observable through KVO! Please listen to the notifications listed in this header or use PSPDFInstantClientDelegate instead.

    Declaration

    Objective-C

    @property (nonatomic, readonly) PSPDFInstantDocumentState documentState;

    Swift

    var documentState: InstantDocumentState { get }
  • Returns (by reference) the value to be assigned as the group of newly created annotations and comments.

    Instant uses this value to set the group of new annotations and comments you create. By default, the value returned by this method corresponds to the default_group claim of the last JWT used to successfully authenticate the receiver. The value can be modified in one of the following ways:

    1. By re-authenticating the receiver using a JWT that contains a different default_group claim.
    2. By calling -overrideDefaultGroupWithValue:error: override the value from the JWT.
    3. By calling -resetDefaultGroup:error:, to undo any prior call to -overrideDefaultGroupWithValue:error:

    This method will fail when the receiver has not been downloaded yet, or when it has already been invalidated.

    Note

    Because nil is a valid value for the default group, this method returns by reference. So while the pointer you pass must not be NULL, we may well populate it with a nil value.

    Declaration

    Objective-C

    - (BOOL)getDefaultGroup:(out NSString *_Nullable *_Nonnull)defaultGroup
                      error:(NSError *_Nullable *_Nullable)error;

    Parameters

    defaultGroup

    A pointer to be populated with the currently active group when this method returns YEScannot be NULL.

    error

    A pointer to be populated with an error detailing why retrieving the default group failed when this method returns NO. @returns Returns whether or not the default group could be read and has been stored in the out parameter.

  • Temporarily overrides the group to use when creating a new annotation or comment.

    By default, Instant uses the default_group claim of the last JWT used to successfully authenticate the receiver to set the group of new annotations and comments you create. In order to assign a different group without having to re- authenticate, you can use this method specifying the desired alternative value. Upon success, i.e. when this method returns YES, the override will be in effect until you call -resetDefaultGroup:error:.

    This method will fail when the receiver has not been downloaded yet, or has already been invalidated.

    Note

    If you don’t have permission to change the group of annotations or comments the server will reject these objects, leading to their deletion.

    Declaration

    Objective-C

    - (BOOL)overrideDefaultGroupWithValue:(nullable NSString *)defaultGroup
                                    error:(NSError *_Nullable *_Nullable)error;

    Parameters

    defaultGroup

    The value to use instead of the default_group claim from the JWT used to authenticate the receiver.

    error

    A pointer to populate with an error when this method returns NO.

  • Resets the default group to the value from the last successfully authenticated JWT for this layer, optionally returning it by reference.

    Call this method to undo the effect of any previous call to -overrideDefaultGroupWithValue:error: on the receiver. When the call succeeds, the group that will be in effect is returned via the first parameter if you didn’t pass NULL.

    This method will fail when the receiver has not been downloaded yet, when it has already been invalidated, or when reading the value from local storage failed.

    Note

    Because nil is a valid value for the default group, this method returns the value that will be in effect by reference.

    Declaration

    Objective-C

    - (BOOL)resetDefaultGroup:(out NSString *_Nullable *_Nullable)defaultGroup
                        error:(NSError *_Nullable *_Nullable)error;

    Parameters

    defaultGroup

    A pointer to be populated with the group that is in effect when this call succeeds. Pass NULL if you’re not interested in this value.

    error

    A pointer to populate with an error when this method returns NO.

    Return Value

    Returns whether or not the value from the default_group claim has been restored.

  • Starts asynchronously downloading the PDF file and annotation data from PSPDFKit Server.

    When the download completes successfully, the PSPDFInstantDidFinishDownloadNotification will be posted. If it fails, PSPDFInstantDidFailDownloadNotification will be posted, containing the error in its user info dictionary.

    Should the PDF file and annotation data already be available locally, no download will be attempted. Instead this method with fail with PSPDFInstantErrorAlreadyDownloaded. If a download is already in progress but has not finished yet, this method will succeed without starting a duplicate download.

    This method will fail with PSPDFInstantErrorInvalidJWT if the value you passed cannot be decoded, or the decoded data relates to another layer. It will fail with PSPDFInstantErrorUserIDMismatch if the decoded user ID is incompatible with the receiver’s value.

    Declaration

    Objective-C

    - (BOOL)downloadUsingJWT:(nonnull NSString *)JWT
                       error:(NSError *_Nullable *_Nullable)error;

    Swift

    func download(usingJWT JWT: String) throws

    Parameters

    JWT

    A JWT that grants access to the layer represented by the receiver. This must be supplied by your own server.

  • The progress of the PDF and annotation download — may be used to cancel an in-progress download.

    This will be nil if when the PDF file and annotation have been downloaded.

    Note

    Important: The progress object should be considered read-only! Do not modify the totalUnitCount, completedUnitCount, cancellationHandler or other properties, and do not add any child progress objects.

    Declaration

    Objective-C

    @property (readonly, nullable) NSProgress *downloadProgress;

    Swift

    var downloadProgress: Progress? { get }
  • Attempts to explicitly start the content migration for the given document descriptor.

    You can use this API to recover from PSPDFInstantErrorContentMigrationNeeded after a failed programmatic sync of the receiver. The migration is performed asynchronously.

    Note

    This call will fail with PSPDFInstantErrorPerformingContentMigration when a migration is already in progress.

    Declaration

    Objective-C

    - (nullable NSProgress *)attemptContentMigration:
        (NSError *_Nullable *_Nullable)error;

    Swift

    func attemptContentMigration() throws -> Progress
  • The progress of the active content migration — if any.

    In general, expect this to be nil.

    Note

    Important: The progress object should be considered read-only! Do not modify the totalUnitCount, completedUnitCount, cancellationHandler or other properties, and do not add any child progress objects.

    Declaration

    Objective-C

    @property (readonly, nullable) NSProgress *migrationProgress;

    Swift

    var migrationProgress: Progress? { get }
  • Returns a PDF document, in which annotations may be edited.

    This returns an object even before the PDF and annotation data have been downloaded, so it can be set on a PSPDFInstantViewController immediately, which then shows the download progress. To start a download, use -downloadUsingJWT:error:.

    Some features of Document are not supported in documents managed by Instant:

    • Archiving with NSCoding: instead archive the JWT for the document descriptor’s identifier and layerName, and recreate the document by calling this method again.
    • Undo
    • Bookmarks
    • The document editor
    • Saving: only annotations may be modified, which are persisted automatically by Instant.

    There can only be a single editable document for a document descriptor at any time! Therefore, this method may return the same instance on repeated calls. If you need to display more than one instance of the same document at a time, for example when you want mirroring on an external screen, create secondary read-only instances using -readOnlyDocument.

    Objects returned by this method become invalid if the download fails, is cancelled, or when removing local storage for the document. In these cases the document instance may no longer be used. Since there can only be one editable document, you must release all references to the invalid document so it deallocates, then request a new one from this method.

    Warning

    Instant uses a special annotation provider for its documents! As a result the annotation manager of this document will not have a fileAnnotationProvider.

    Declaration

    Objective-C

    @property (nonatomic, readonly) PSPDFDocument *_Nonnull editableDocument;

    Swift

    var editableDocument: Document { get }
  • Returns a read-only PDF document for this editing context.

    There can only be a single editable Instant-enabled Document for a document descriptor at a time. But since one Document should only be used by one PDFViewController, there will be times — like mirroring on an external display — where you need more than just one. For these situations, you can get an arbitrary number of documents that are read-only:
    When changes are made, these are updated as appropriate, but they will not allow you to make any edits — like adding, changing, or removing existing annotations.

    Otherwise this behaves the same as editableDocument.

    Warning

    Instant uses a special annotation provider for its documents! As a result the annotation manager of this document will not have a fileAnnotationProvider.

    Declaration

    Objective-C

    - (nonnull PSPDFDocument *)readOnlyDocument;

    Swift

    func readOnlyDocument() -> Document
  • Removes the annotation store from disk.

    Calling this method will also cancel any in-progress network operations for this document descriptor. Removing the annotation store may fail if the file-system operations fail.

    Warning

    This method must be called before authenticating the document descriptor as a different user. Providing an authentication token for a different user without calling this method first may raise an exception.

    Declaration

    Objective-C

    - (BOOL)removeLocalStorageWithError:(NSError *_Nullable *_Nullable)error;

    Swift

    func removeLocalStorage() throws
  • Attempts to reauthenticate the receiver using the given JWT.

    Instant does not permanently store authentication information but it does cache it in memory. As a result, you will rarely have to call this method repeatedly on the same object during the a single run of your app. In particular, a freshly downloaded document descriptor is already authenticated — as downloading requires authentication.

    As a general rule, it is only necessary to call this method after -[PSPDFInstantClientDelegate instantClient:documentDidFailAuthentication:] has been called:
    This will happen as soon as a sync operation fails due to an authentication error.

    You can, however, pro-actively call this method for every local document descriptor when your app starts. This may be useful to limit the number of requests that have to be made if, for example, you have stored the JWTs for your layers in the keychain, or your server backend provides an endpoint returning the JWTs for all of the layers a user may access in a single call.

    Declaration

    Objective-C

    - (void)reauthenticateWithJWT:(nonnull NSString *)JWT;

    Swift

    func reauthenticate(withJWT JWT: String)
  • Returns the unique identifier for the given annotation of one of the receiver’s documents.

    You can use this method to — for example — associate data from arbitrary sources with annotations managed by Instant. Annotations created interactively by the user working on the editableDocument in a PDFViewController always have an identifier. If, however, you create a new annotation programmatically, the identifier will be available as soon as you add the annotation to the receiver’s editableDocument.
    Identifiers returned from this method are guaranteed to be stable over time, and unique in the context of the document descriptor they belong to. Although they are typed as strings for interoperability, you should treat them as opaque objects. Due to deliberate design considerations on our part, they are URL-, XML-, and filesystem-safe.

    This method will fail if the annotation does not belong to any of the receiver’s documents. It may also fail if the receiver is no longer valid.

    Declaration

    Objective-C

    - (nullable NSString *)
        identifierForAnnotation:(nonnull PSPDFAnnotation *)annotation
                          error:(NSError *_Nullable *_Nullable)error;

    Swift

    func identifier(for annotation: Annotation) throws -> String

    Parameters

    annotation

    The annotation to identify.

  • Returns the annotation for the given identifer and document — if any.

    This method allows you to use values once returned from -identifierForAnnotation:error: for looking up annotations in a document managed by the receiver. As useful annotations are always related to a document, you have to specify which document that the annotation — if found — should belong to.
    As such, calling this method will fail if the document you passed is not managed by the receiver, or if there is no annotation with the specified identifier. It will also fail if the document has not been dowloaded yet.

    Declaration

    Objective-C

    - (nullable PSPDFAnnotation *)
        annotationWithIdentifier:(nonnull NSString *)identifier
                     forDocument:(nonnull PSPDFDocument *)document
                           error:(NSError *_Nullable *_Nullable)error;

    Swift

    func annotation(withIdentifier identifier: String, for document: Document) throws -> Annotation

    Parameters

    identifier

    The unique identifier of the annotation to return.

    document

    The document to which the returned annotation — if any — belongs.

  • Syncs annotations with the PSPDFKit Server.

    When the PDF file and annotation data have been downloaded, this method initiates a one-time sync cycle:
    Sync requests will be made until all local changes have been synced, until an error occurs, or until you call -stopSyncing:. If you are using PSPDFInstantViewController in its default configuration to display the document, there is no need to call this method. Instant will push edits to the server as they happen and will listen for changes from the server.

    This method allows you to sync a document descriptor that is not being displayed or for whose document(s) you have disabled automatic syncing. Automatic syncing is controlled by PSPDFInstantViewController.shouldListenForServerChangesWhenVisible and delayForSyncingLocalChanges.

    Note

    This method does nothing if the PDF file or annotations have not been downloaded yet.

    Declaration

    Objective-C

    - (void)sync;

    Swift

    func sync()
  • Stops the current sync cycle, optionally cancelling the current request.

    Calling this method is only necessary if you choose to sync manually. That is:

    If your answer to all of the above is yes, you may call this method to stop the current sync cycle. Passing false will allow the current request to complete. This gives you the latest server state, but you may still have local changes that have not been synced.
    Passing true will cancel the current request immediately. Your view of the server’s state will most likely be outdated and if you had local changes, the server has probably not seen them yet.

    Declaration

    Objective-C

    - (void)stopSyncing:(BOOL)cancelCurrentRequest;

    Swift

    func stopSyncing(_ cancelCurrentRequest: Bool)

    Parameters

    cancelCurrentRequest

    Whether the current request should be cancelled — even if it is receiving data.

  • Delay in seconds before kicking off automatic sync after local changes are made to the editableDocument’s annotations.

    If this is a positive value, Instant will automatically sync annotations with the PSPDFKit Server after annotations in the document are modified. Setting this to a higher value will reduce the load on the network and reduce energy use but means other users will not see annotation updates as soon, which also increases the chance of sync conflicts. Setting this to a positive value less than 1 second may strain the network and battery and is not recommended.

    Set this to PSPDFInstantSyncingLocalChangesDisabled to disable automatic syncing, in which case annotations must be synchronized manually by calling sync.

    Setting this to zero will not result in immediate syncing and is not supported. Attempting to sync immediately after every change would stress the network and be unlikely to result in faster syncing.

    Defaults to 1 second.

    Declaration

    Objective-C

    @property NSTimeInterval delayForSyncingLocalChanges;

    Swift

    var delayForSyncingLocalChanges: TimeInterval { get set }
  • Tells the receiver to start listening for changes from the server as they happen.

    Once a document descriptor’s data has been downloaded, you can use this method to begin observing the server for changes. The most common use case for this is that you are displaying the document in your custom PDF view controller, and you want to make sure that the user sees changes made on other devices in a real-time-like fashion. When you call this method, Instant will begin monitoring the server for changes until syncing fails, or until you call -stopListeningForServerChanges — whichever happens first.

    A word of warning:
    Using the network, especially the cellular network, is one of the most energy intensive tasks. While we do our best to minimize the energy impact this feature has, if your app does not require (near-)real-time sync, consider using explicit user actions to call sync instead.

    Note

    If you use PSPDFInstantViewController you get this behavior for free! This method is provided if you cannot customize that class to suit your needs, but need real-time-like updates.

    Declaration

    Objective-C

    - (void)startListeningForServerChanges;

    Swift

    func startListeningForServerChanges()
  • Tells the receiver to stop listening for changes from the server.

    Once you are no longer interested in real-time updates from the server, use this method to stop listening for changes. A common scenario where you would want to call this, is when you stop displaying an Instant enabled document in your custom PDF view controller.

    Note

    If you use PSPDFInstantViewController you get this behavior for free! This method is provided if you cannot customize that class to suit your needs, but need real-time updates.

    Declaration

    Objective-C

    - (void)stopListeningForServerChanges;

    Swift

    func stopListeningForServerChanges()