Undo/Redo Support

PSPDFKit for iOS supports undo/redo for creating and editing annotations. (This includes form filling)

To achieve this, the SDK uses a standard component named NSUndoManager. We recommend studying both Apple's Documentation and the NSHipster article to understand the principles how this class works if you never used it before.

PSPDFKit uses a PSPDFUndoController object which wraps and manages the undo manager and allows more convenient access to properties such as canUndo.

The undo controller also extends Apple's concept by adding a timed coalescing mode, which merges undo changes. This is used in various places, for example when a color is chosen from the color picker, we don't save every single change but commit the change after a short period of time to have a better undo/redo experience for the user. This implies that whenever the PSPDFUndoController object exposes properties, you should use these and only in cases where there's no other way go down to the wrapped undo manager instance.

The PSPDFUndoController instance is exposed via the undoController property on PSPDFDocument. Undo can also be disabled on a per-document level via the undoEnabled property.

Listening to Undo/Redo changes

If you're implementing your own undo/redo buttons and are trying to update the enabled state, you need to listen for following notifications:

  • NSUndoManagerDidUndoChangeNotification
  • NSUndoManagerDidRedoChangeNotification
  • PSPDFUndoControllerAddedUndoActionNotification
  • PSPDFUndoControllerRemovedUndoActionNotification

For convenience reasons, we also expose a delegate method on PSPDFAnnotationStateManager that listens to the set above and calls back with the undo/redo enabled states:

optional public func annotationStateManager(_ manager: PSPDFAnnotationStateManager, didChangeUndoState undoEnabled: Bool, redoState redoEnabled: Bool)
- (void)annotationStateManager:(PSPDFAnnotationStateManager *)manager didChangeUndoState:(BOOL)undoEnabled redoState:(BOOL)redoEnabled;

Note that this class supports multiple delegates, use addDelegate: and removeDelegate: to register them.

See PSCVerticalAnnotationToolbarExample.m for a sample implementation of custom undo/redo buttons.

Shake to Undo

PSPDFKit is a good iOS citizen and supports the native ways of undoing, which on the iPhone is shake to undo. See this article in the iOS Human Interface Guidelines.. Shake to Undo can be both deactivated from the user in the phone Accessibility settings or via the applicationSupportsShakeToEdit property on UIApplication.

On iPad we support the native undo button on the keyboard.

Implementation Notes

Saving annotations will clear the undo/redo stack. Writing objects into the PDF changes various details, and providing a reliable undo would be very difficult. Saving happens at various points, including when the application enters the background.

On a technical level, our undo/redo works via using KVO and registering each annotation object and tracking changes on a property-basis.