Detecting If Annotations Have Changed

PSPDFKit allows you to edit and create annotations if your license includes this feature. You can detect changes to the underlying data models by listening to the following notifications:

Copy
1
2
3
4
5
6
7
8
9
/// Sent when new annotations are added to/removed from the default `PSPDFFileAnnotationProvider`.
public let PSPDFAnnotationsAddedNotification: String // object = array of new `PSPDFAnnotation(s)`.
public let PSPDFAnnotationsRemovedNotification: String // object = array of removed `PSPDFAnnotation(s)`.

/**
 Internal events to notify the annotation providers when annotations are being changed.
 @warning Only send from main thread! Don't call save during a change notification.
 */
public let PSPDFAnnotationChangedNotification: String // object = new `PSPDFAnnotation`.
Copy
1
2
3
4
5
6
7
8
9
/// Sent when new annotations are added to/removed from the default `PSPDFFileAnnotationProvider`.
PSPDF_EXPORT NSNotificationName const PSPDFAnnotationsAddedNotification; // object = array of new `PSPDFAnnotation(s)`.
PSPDF_EXPORT NSNotificationName const PSPDFAnnotationsRemovedNotification; // object = array of removed `PSPDFAnnotation(s)`.

/**
 Internal events to notify the annotation providers when annotations are being changed.
 @warning Only send from main thread! Don't call save during a change notification.
 */
PSPDF_EXPORT NSNotificationName const PSPDFAnnotationChangedNotification; // object = new `PSPDFAnnotation`.

Here’s an example of listening to changes of the contents in the note annotation controller:

Copy
1
2
3
4
5
6
7
8
9
func annotationChangedNotification(notification: Notification) {
    // Check if we need to rerender ourselves.
    let changedAnnotation = notification.object as! PSPDFAnnotation
    if annotation == changedAnnotation, let keyPaths = notification.userInfo?[PSPDFAnnotationChangedNotificationKeyPathKey] as? [String] {
        if keyPaths.count > 1 || keyPaths.first != "contents" {
            updateImage(animated: true)
        }
    }
}
Copy
1
2
3
4
5
6
7
8
9
- (void)annotationChangedNotification:(NSNotification *)notification {
    // Check if we need to rerender ourselves.
    if ([self.annotation isEqual:notification.object]) {
        NSArray *keyPaths = notification.userInfo[PSPDFAnnotationChangedNotificationKeyPathKey];
        if (keyPaths.count > 1 || ![keyPaths.firstObject isEqual:@"contents"]) {
            [self updateImageAnimated:YES];
        }
    }
}

In PSPDFKit, annotations are usually created using PSPDFAnnotationStateManager. If you create a drawing, the state manager is in the draw mode and will cache drawn lines until you exit the draw state, which will, in turn, cause a PSPDFInkAnnotation object to be created. After creation, an undo operation will remove the entire annotation — but while you’re in the drawing mode, undo/redo operates on a finer level, affecting one stroke at a time.

If you change annotations, make sure to also post appropriate change notifications. See our guide on The Annotation Object Model for details.

Detecting User Input in Form Fields

Because form fields are based on annotations, you can also use PSPDFAnnotationChangedNotification to listen for user input:

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func annotationChanged(_ notification: Notification) {
    // Make sure it was a text field that changed.
    guard let annotation = notification.object as? PSPDFTextFieldFormElement else {
        return
    }
    // Make double sure that the annotation is in the currently handled document.
    guard annotation.document === document else {
        return
    }
    // Make sure that the contents, and not the style, changed.
    guard let keyPaths = notification.userInfo?[PSPDFAnnotationChangedNotificationKeyPathKey] as? [String], keyPaths.contains("contents") else {
        return
    }
    // Handle the change.
    print("Text field content changed:", annotation.contents)
}
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (void)annotationChanged:(NSNotification *)notification {
    // Extract the notification content for further use.
    PSPDFAnnotation *annotation = (PSPDFAnnotation *)notification.object;
    NSArray<NSString *> *keyPaths = notification.userInfo[PSPDFAnnotationChangedNotificationKeyPathKey];
    // Make sure it was a text field that changed.
    if (![notification.object isKindOfClass:PSPDFTextFieldFormElement.class]) {
        return;
    }
    // Make double sure that the annotation is in the currently handled document.
    // Direct pointer comparison used on purpose.
    if (annotation.document != self.document) {
        return;
    }
    // Make sure that the contents, and not the style, changed.
    if (![keyPaths containsObject:@"contents"]) {
        return;
    }
    // Handle the change.
    NSLog(@"Text field content changed: %@", annotation.contents);
}

The above technique can also be used to listen for changes in other types of form fields. See Introduction to Forms to learn more about form support in PSPDFKit.