Undo and Redo
PSPDFKit for iOS supports undo and redo for creating and editing annotations, including form filling. Users can undo and redo changes using the buttons in
To achieve this, the SDK uses a standard component named
NSUndoManager. If you have never used it before, we recommend studying both the Apple Documentation and the NSHipster article about this topic to understand the principles of how this class works.
The undo controller also extends Apple’s concept by adding a coalescing mode, which merges changes happening in quick succession into a single undo event. This is used in various places — for example, when a color is chosen from the color picker, we don’t save every single change. Rather we commit the change after a short period of time to provide a better undo experience for the user. This implies that whenever the
PSPDFUndoController object exposes properties, you should use them, and only in cases where there’s no other way to go down to the wrapped undo manager instance.
Listening for Undo and Redo Changes
If you’re implementing your own undo and redo buttons and are trying to update the enabled state, you need to listen for the following notifications:
optional public func annotationStateManager(_ manager: PSPDFAnnotationStateManager, didChangeUndoState undoEnabled: Bool, redoState redoEnabled: Bool)
- (void)annotationStateManager:(PSPDFAnnotationStateManager *)manager didChangeUndoState:(BOOL)undoEnabled redoState:(BOOL)redoEnabled;
PSCVerticalAnnotationToolbarExample.m for a sample implementation of custom undo and 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 the Undo and Redo section in the iOS Human Interface Guidelines for more on this. Shake to Undo can be deactivated by the user in the phone Accessibility settings or via the
applicationSupportsShakeToEdit property on
Saving annotations will clear the undo and redo stacks. As a result, writing objects into the PDF changes various details, so providing a reliable undo is difficult. Saving happens at various points, including when the application enters the background.
On a technical level, our undo works via KVO and registering each annotation object and tracking changes on a property basis.