Using a Custom Annotation Provider in Swift for iOS
A custom annotation provider that serializes its annotations. Useful when annotations are loaded from a URL. Get additional resources by visiting our guide on saving PDF annotations to external storage in iOS.
//// Copyright © 2019-2025 PSPDFKit GmbH. All rights reserved.//// The Nutrient sample applications are licensed with a modified BSD license.// Please see License for details. This notice may not be removed from this file.//
import PSPDFKitimport PSPDFKitUI
class AnnotationProviderWithRotationExample: Example {
override init() { super.init()
title = "Custom Annotation Provider With Serialization and Rotation" contentDescription = "A custom annotation provider that serializes its annotations shown working with temporary page rotations." category = .annotationProviders }
override func invoke(with delegate: ExampleRunnerDelegate) -> UIViewController { let document = AssetLoader.document(for: AssetName.welcome) document.didCreateDocumentProviderBlock = { documentProvider in let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first! let dataDirectory = cachesDirectory.appendingPathComponent("AnnotationProviderWithRotationExample", isDirectory: true) try! FileManager.default.createDirectory(at: dataDirectory, withIntermediateDirectories: true, attributes: nil) let storageURL = dataDirectory.appendingPathComponent("\(document.uid!).annotations", isDirectory: false)
let customProvider = AnnotationProvider(storageFileURL: storageURL, documentProvider: documentProvider) // Include the default file annotation provider so it can load links and form elements from the PDF. let fileAnnotationProvider = documentProvider.annotationManager.fileAnnotationProvider! documentProvider.annotationManager.annotationProviders = [customProvider, fileAnnotationProvider] } return RotatePageTemporarilyExample.RotatePagePDFViewController(document: document) { $0.pageMode = .single } }
/// A custom annotation provider that loads from, and saves to, a file. /// /// This is only useful as an example. In practice this technique is for when you have a custom annotation backend /// such as a database. If you just want to save annotations to an external file in an archive, do not use a custom /// annotation provider and instead set the document’s `annotationSaveMode` to `PSPDFAnnotationSaveModeExternalFile`. private class AnnotationProvider: PDFContainerAnnotationProvider {
let storageFileURL: URL
init(storageFileURL: URL, documentProvider: PDFDocumentProvider) { self.storageFileURL = storageFileURL super.init(documentProvider: documentProvider)
guard let data = try? Data(contentsOf: storageFileURL) else { // Most likely the file does not exist. Don’t care. return } let annotations = try! NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSArray.self, Annotation.self], from: data) // We don’t want to post any notifications here: there can’t be anyone listening and nothing changed. super.add(annotations as! [Annotation], options: [.suppressNotifications: true]) performWrite { // Adding the annotations may set the save flag but nothing actually changed => Clear the flag. self.clearNeedsSaveFlag() } }
override func saveAnnotations(options: [String: Any]? = nil) throws { let data = try NSKeyedArchiver.archivedData(withRootObject: allAnnotations as NSArray, requiringSecureCoding: true) try data.write(to: storageFileURL) performWriteAndWait { clearNeedsSaveFlag() } } }}
This code sample is an example that illustrates how to use our SDK. Please adapt it to your specific use case.