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:
PSPDFInstantDidFailAuthenticationNotification
when authenticating the editing context failedPSPDFInstantDidFinishReauthenticationNotification
when the editing context has been reauthenticatedPSPDFInstantDidFailReauthenticationNotification
when reauthenticating the editing context failedPSPDFInstantDidFinishDownloadNotification
when the download of the PDF file and associated annotations for a docment descriptor finishesPSPDFInstantDidFailDownloadNotification
when the download of the PDF file or the associated annotations for a document descriptor failsPSPDFInstantDidBeginSyncingNotification
when the document descriptor starts a new sync cyclePSPDFInstantSyncCycleDidChangeStateNotification
when the sync cycle changes its statePSPDFInstantDidFailSyncingNotification
when the sync cycle stops abnormally (reasons include cancellation)PSPDFInstantDidFinishSyncingNotification
when the sync cycle completes successfully
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 fromnil
(no value at all) to a nonnull value through reauthentication with a new JWT that includes theuserd_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 differentuser_id
(or no such claim at all) will fail immediately.This property will be
nil
when your JWTs do not contain theuser_id
claim. It may also benil
, 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 usePSPDFInstantClientDelegate
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:- By re-authenticating the receiver using a JWT that contains a different
default_group
claim. - By calling
-overrideDefaultGroupWithValue:error:
override the value from the JWT. - 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 beNULL
, we may well populate it with anil
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
YES
— cannot beNULL
.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. - By re-authenticating the receiver using a JWT that contains a different
-
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 returnsYES
, 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 passNULL
.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 withPSPDFInstantErrorUserIDMismatch
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 thetotalUnitCount
,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 withPSPDFInstantErrorPerformingContentMigration
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 thetotalUnitCount
,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’sidentifier
andlayerName
, 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 afileAnnotationProvider
.Declaration
Objective-C
@property (nonatomic, readonly) PSPDFDocument *_Nonnull editableDocument;
Swift
var editableDocument: Document { get }
- Archiving with
-
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 oneDocument
should only be used by onePDFViewController
, 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 afileAnnotationProvider
.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 aPDFViewController
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’seditableDocument
.
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 usingPSPDFInstantViewController
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
anddelayForSyncingLocalChanges
.Note
This method does nothing if the PDF file or annotations have not been downloaded yet. -
Stops the current sync cycle, optionally cancelling the current request.
Calling this method is only necessary if you choose to sync manually. That is:
- You have disabled
PSPDFInstantViewController.shouldListenForServerChangesWhenVisible
on every object showing one of the receiver’s documents, - you have set
delayForSyncingLocalChanges
on this object toPSPDFInstantSyncingLocalChangesDisabled
, - you have balanced any call to
-startListeningForServerChanges
with a call to-stopListeningForServerChanges
, and - you have called
sync
.
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.
Passingtrue
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.
- You have disabled
-
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 callingsync
.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 callsync
instead.Note
If you usePSPDFInstantViewController
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 usePSPDFInstantViewController
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()