---
title: "PSPDFKit 9.5 Migration Guide"
canonical_url: "https://www.nutrient.io/guides/ios/migration-guides/pspdfkit-9-5-migration-guide/"
md_url: "https://www.nutrient.io/guides/ios/migration-guides/pspdfkit-9-5-migration-guide.md"
last_updated: "2026-06-19T09:21:00.285Z"
description: "Learn how to update your iOS project to PSPDFKit 9.5 for improved user interactions and compatibility with iOS 12, 13, and preliminary iOS 14 support."
---

This guide covers updating an iOS or Mac Catalyst project from PSPDFKit&nbsp;9.4 for iOS to PSPDFKit&nbsp;9.5 for iOS. We encourage you to update as soon as possible, in order to take advantage of future new features and fixes.

PSPDFKit 9.5 for iOS fully supports iOS 12 and 13, and it includes preliminary compatibility with iOS 14. Xcode 11.5 or later is required to use this version of the SDK. Learn more in our [version support](https://www.nutrient.io/guides/ios/announcements/version-support.md) guide.

## Handling User Interactions

With PSPDFKit 9.5 for iOS, the way user interactions are handled in [`PDFViewController`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfviewcontroller) has been completely revamped to be more powerful and customizable than ever. Under the new [`interactions`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfviewcontroller/interactions) property, you’ll find a selection of **interaction components**, all of which are responsible for handling a single user interaction.

#### Interaction Components Related to Annotations

- [`selectAnnotation`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/selectannotation) — Responsible for selecting annotations.

- [`deselectAnnotation`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/deselectannotation) — Responsible for discarding the current annotation selection.

- [`transformAnnotation`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/transformannotation) — Responsible for moving, resizing, and adjusting selected annotations.

- [`editAnnotation`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/editannotation) — Responsible for initiating the editing of form elements, free text annotations, and link annotations.

- [`openLinkAnnotation`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/openlinkannotation) — Responsible for “opening” link annotations, i.e. executing their actions.

#### Interaction Components Related to Text Selection

- [`selectText`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/selecttext) — Responsible for initiating and changing text selection.

- [`deselectText`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/deselecttext) — Responsible for discarding the current text selection.

#### Miscellaneous Interaction Components

- [`fastScroll`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/fastscroll) — Responsible for changing pages by tapping near the edge of the document.

- [`smartZoom`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/smartzoom) — Responsible for zooming in on and out of content on a page.

- [`toggleUserInterface`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/toggleuserinterface) — Responsible for toggling the user interface.

#### Interaction Components Composed of Other Components

There are also three interaction components that are composed of other interaction components. You can use them to conveniently customize several interaction components at once:

- [`allAnnotationInteractions`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/allannotationinteractions) — Composed of all interaction components related to annotations.

- [`allTextInteractions`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/alltextinteractions) — Composed of all interaction components related to text selection.

- [`allInteractions`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/allinteractions) — Composed of all interaction components.

### Customizing Conditions of User Interactions

You can take advantage of **activation conditions** to allow or disallow certain interaction components to proceed. Activation condition closures have three parameters: a `context` object that provides information about a user interaction; a `point` at which it is taking place; and a [`coordinateSpace`](https://developer.apple.com/documentation/uikit/uicoordinatespace) in which the aforementioned `point` is provided. For example, to disallow selecting annotations on a certain page, you can write the following:

```swift

interactions.selectAnnotation.addActivationCondition { context, point, coordinateSpace in
    return context.pageView.pageIndex!= 0
}

```

Some interaction components, like [`toggleUserInterface`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/toggleuserinterface), have no additional information they can provide except a `point` and a [`coordinateSpace`](https://developer.apple.com/documentation/uikit/uicoordinatespace). Therefore, the type of the `context` parameter of their activation condition and callback closures will be `NSNull`.

If you want to completely disable an interaction component, instead of adding an activation condition that returns `false`, you can use its [`isEnabled`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/interactioncomponent/isenabled) property. For example, the following line will disable all user interactions related to annotations:

```swift

interactions.allAnnotationInteractions.isEnabled = false

```

### Responding to User Interactions

If you want to respond to a certain user interaction without modifying its behavior, you can take advantage of **activation callbacks**. Activation callback closures have the exact same parameters as activation condition closures and are executed just before a user interaction takes place. For example, to print a console message every time a smart zoom is performed, you can write the following:

```swift

interactions.selectAnnotation.addActivationCallback { context, point, coordinateSpace in
    print("Will smart zoom to rect: \(context.targetRect) in scroll view: \(context.scrollView).")
}

```

Make sure you’re not creating any strong reference cycles when using activation conditions and callbacks. If you’re adding them in a [`PDFViewController`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfviewcontroller) subclass and you need to call `self` from within, make sure to capture it weakly using `[weak self]`. For more information about strong reference cycles in closures, check out the [Automatic Reference Counting](https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html#ID56) article.

### Using Your Own Gesture Recognizers

The new user interaction handling mechanism introduced in PSPDFKit 9.5 for iOS was designed to work seamlessly with your own gesture recognizers. The interaction components provide a set of functions you can use to set up both failure and simultaneous recognition relationships between it and your own gesture recognizers.

For example, to add a long-press gesture recognizer that takes priority over selecting text but should only begin if selecting an annotation failed, you can write the following:

```swift

// Create your gesture recognizer.
let gestureRecognizer = UILongPressGestureRecognizer()
gestureRecognizer.addTarget(self, action: #selector(longPressGestureRecognizerDidChangeState))

gestureRecognizer.delegate = self

// Set up the failure requirements.
gestureRecognizer.require(toFail: interactions.selectAnnotation)
interactions.selectText.require(toFail: gestureRecognizer)

// Add your gesture recognizer to the document view controller's view.
documentViewController?.view.addGestureRecognizer(gestureRecognizer)

// Decide whether your gesture recognizer should begin.
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    return /* condition */
}

// Perform your action.
@objc func longPressGestureRecognizerDidChangeState(_ gestureRecognizer: UIGestureRecognizer) {
    /* action */
}

```

Using the [`gestureRecognizerShouldBegin(_:)`](https://developer.apple.com/documentation/uikit/uigesturerecognizerdelegate/1624213-gesturerecognizershouldbegin) delegate method is crucial if you’re setting up requirements between the built-in interaction components and your own gesture recognizer. If you don’t implement it, your gesture recognizer will never fail, fulfilling the failure requirement and effectively blocking the interaction component that depends on it from ever proceeding. To learn more, check out the articles on [coordinating multiple gesture recognizers](https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/coordinating_multiple_gesture_recognizers/) and the [gesture recognizer state machine](https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/implementing_a_custom_gesture_recognizer/about_the_gesture_recognizer_state_machine).

You can also have your own gesture recognizer work simultaneously with the built-in interaction components. For example, to add a double-tap gesture recognizer that doesn’t block smart zoom, you can write the following:

```swift

// Create your own gesture recognizer.
let gestureRecognizer = UITapGestureRecognizer()
gestureRecognizer.addTarget(self, action: #selector(doubleTapGestureRecognizerDidChangeState))

gestureRecognizer.numberOfTapsRequired = 2

// Set up the simultaneous recognition relationship with smart zoom.
interactions.smartZoom.allowSimultaneousRecognition(with: gestureRecognizer)

// Add your gesture recognizer to the document view controller's view.
documentViewController?.view.addGestureRecognizer(gestureRecognizer)

// Perform your action.
@objc func doubleTapGestureRecognizerDidChangeState(_ gestureRecognizer: UIGestureRecognizer) {
    /* action */
}

```

For more information on how to use the interaction component activation conditions, callbacks, and your own gesture recognizers to achieve specific outcomes, check out the migration cases below.

## Migration Cases for Handling User Interactions

### Observing Tap and Long-Press Gestures

If you previously used [`pdfViewController(_:didTapOn:at:)`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfviewcontrollerdelegate), [`singleTapped(_:)`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfpageview), or [`singleTapped(at:)`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfpageview) to observe tap gestures, you must now use your own [`UITapGestureRecognizer`](https://developer.apple.com/documentation/uikit/uitapgesturerecognizer) and set up its relationship with the built-in interaction components:

```swift

// Before you would have...
func pdfViewController(_ pdfController: PDFViewController, didTapOn pageView: PSPDFPageView, at viewPoint: CGPoint) -> Bool {
    print("Tapped at point: \(viewPoint) in page view: \(pageView)")
    return false
}

```

```swift

// Now, set up your gesture recognizer.
let gestureRecognizer = UITapGestureRecognizer()
gestureRecognizer.addTarget(self, action: #selector(tapGestureRecognizerDidChangeState))

// Make it work simultaneously with all built-in interaction components.
interactions.allInteractions.allowSimultaneousRecognition(with: gestureRecognizer)

// Add your gesture recognizer to the document view controller's view.
documentViewController?.view.addGestureRecognizer(gestureRecognizer)

// Perform your action.
@objc func tapGestureRecognizerDidChangeState(_ gestureRecognizer: UITapGestureRecognizer) {
    if gestureRecognizer.state ==.ended, let documentViewController = documentViewController {
        if let pageView = documentViewController.visiblePageView(at: gestureRecognizer.location(in: documentViewController.view)) {
            print("Tapped at point: \(gestureRecognizer.location(in: pageView)) in page view: \(pageView)")
        }
    }
}

```

Similarly, if you previously used [`pdfViewController(_:didLongPressOn:at:gestureRecognizer)`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfviewcontrollerdelegate) or [`longPress(_:)`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfpageview) to observe long-press gestures, you must now use your own [`UILongPressGestureRecognizer`](https://developer.apple.com/documentation/uikit/uilongpressgesturerecognizer):

```swift

// Create your own gesture recognizer.
let gestureRecognizer = UILongPressGestureRecognizer()
gestureRecognizer.addTarget(self, action: #selector(longPressGestureRecognizerDidChangeState))

// Make the gesture recognizer work simultaneously with all interactions.
interactions.allInteractions.allowSimultaneousRecognition(with: gestureRecognizer)

// Add your gesture recognizer to the document view controller's view.
documentViewController?.view.addGestureRecognizer(gestureRecognizer)

// Perform your action.
@objc func longPressGestureRecognizerDidChangeState(_ gestureRecognizer: UILongPressGestureRecognizer) {
    if gestureRecognizer.state ==.began {
        print("Long press began at point: \(gestureRecognizer.location(in: view))")
    } else if gestureRecognizer.state ==.ended {
        print("Long press ended at point: \(gestureRecognizer.location(in: view))")
    }
}

```

If you used the above methods and relied on their return value to conditionally prevent default gesture handling from proceeding, you must set up a failure relationship with all built-in interaction components instead:

```swift

// Before you would have...
func pdfViewController(_ pdfController: PDFViewController, didTapOn pageView: PSPDFPageView, at viewPoint: CGPoint) -> Bool {
    guard /* condition */ else {
        return true
    }
    /* action */
    return false
}

```

```swift

// Now, create your own gesture recognizer.
let gestureRecognizer = UITapGestureRecognizer()
gestureRecognizer.addTarget(self, action: #selector(tapGestureRecognizerDidChangeState))

gestureRecognizer.delegate = self

// Make it work simultaneously with all built-in interaction components.
interactions.allInteractions.require(toFail: gestureRecognizer)

// Add your gesture recognizer to the document view controller's view.
documentViewController?.view.addGestureRecognizer(gestureRecognizer)

// Move the condition out to the delegate method.
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    return /* reverse condition */
}

// Perform your action.
@objc func tapGestureRecognizerDidChangeState(_ gestureRecognizer: UITapGestureRecognizer) {
    if gestureRecognizer.state ==.ended {
        /* action */
    }
}

```

Both the [`gestureRecognizerShouldBegin(_:)`](https://developer.apple.com/documentation/uikit/uigesturerecognizerdelegate/1624213-gesturerecognizershouldbegin) delegate method and interaction component activation conditions require a `true` return value to proceed. If you previously used the return value of `true` to disable the default touch handling, remember to invert that condition now.

### Customizing Tappable Annotations

If you previously used [`tappableAnnotations(at:)`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfpageview) or [`tappableAnnotationsForLongPress(at:)`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfpageview) to customize which annotations can be selected, you can now take advantage of interaction component activation conditions to do it:

```swift

// Before you would have...
override func tappableAnnotations(at viewPoint: CGPoint) -> [Annotation] {
    super.tappableAnnotations(at: viewPoint).filter { annotation in!(annotation is InkAnnotation)
    }
}

```

```swift

// Now, add an activation condition to the interaction component responsible for selecting annotations.
interactions.selectAnnotation.addActivationCondition { context, point, coordinateSpace in!(context.annotation is InkAnnotation)
}

// If you want to disable editing certain annotations, you can also add a condition to the `editAnnotation` interaction component.
interactions.editAnnotation.addActivationCondition { context, point, coordinateSpace in!(context.annotation is LinkAnnotation)
}

```

The distinction between “tappable annotations” and “tappable annotations for long-press” is gone in PSPDFKit 9.5 for iOS.

### Using a Double-Tap Gesture to Select Annotations

You can use your own gesture recognizers to replace some of the built-in interaction components. For example, to use a double-tap (instead of a single-tap) gesture to select annotations, you can write the following:

```swift

// Disable the interaction component responsible for selecting annotations.
interactions.selectAnnotation.isEnabled = false

// Set up your own double-tap gesture recognizer.
let gestureRecognizer = UITapGestureRecognizer()
gestureRecognizer.addTarget(self, action: #selector(doubleTapGestureRecognizerDidChangeState))

gestureRecognizer.numberOfTapsRequired = 2
gestureRecognizer.delegate = self

// Set up a failure relationship with text selection and smart zoom, since they can also recognize double-tap gestures.
interactions.selectText.require(toFail: gestureRecognizer)
interactions.smartZoom.require(toFail: gestureRecognizer)

// Add your gesture recognizer to the document view controller's view.
documentViewController?.view.addGestureRecognizer(gestureRecognizer)

// Allow your gesture recognizer to proceed only if there is a selectable annotation.
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    interactions.selectAnnotation.canActivate(at: gestureRecognizer.location(in: view), in: view)
}

// Perform annotation selection once the gesture is recognized.
@objc func doubleTapGestureRecognizerDidChangeState(_ gestureRecognizer: UIGestureRecognizer) {
    if gestureRecognizer.state ==.ended {
        interactions.tryToSelectAnnotation(at: gestureRecognizer.location(in: view), in: view)
    }
}

```

You can apply the same thought process to use different gestures for other built-in interaction components.

## Further Reading

For more information about the new user interaction handling mechanism, check out the documentation of the [`PSPDFDocumentViewInteractions`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions) protocol and the [`PSPDFInteractionComponent`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/interactioncomponent) class.

## API Changes

- Removed: `PSPDFViewControllerDelegate.pdfViewController(_:didTapOn:at:)`\
  _See the [Observing Tap and Long-Press Gestures](#observing-tap-and-long-press-gestures) section._

- Removed: `PSPDFViewControllerDelegate.pdfViewController(_:didLongPressOn:at:gestureRecognizer:)`\
  _See the [Observing Tap and Long-Press Gestures](#observing-tap-and-long-press-gestures) section._

- Removed: `PDFPageView.singleTapped(_:)`\
  _See the [Observing Tap and Long-Press Gestures](#observing-tap-and-long-press-gestures) section._

- Removed: `PDFPageView.singleTapped(at:)`\
  _See the [Observing Tap and Long-Press Gestures](#observing-tap-and-long-press-gestures) section._

- Removed: `PDFPageView.longPress(_:)`\
  _See the [Observing Tap and Long-Press Gestures](#observing-tap-and-long-press-gestures) section._

- Removed: `PDFPageView.tappableAnnotations(at:)`\
  _See the [Customizing Tappable Annotations](#customizing-tappable-annotations) section._

- Removed: `PDFPageView.tappableAnnotationsForLongPress(at:)`\
  _See the [Customizing Tappable Annotations](#customizing-tappable-annotations) section._
---

## Related pages

- [14 9 Migration Guide](/guides/ios/migration-guides/14-9-migration-guide.md)
- [Pspdfkit 10 4 Migration Guide](/guides/ios/migration-guides/pspdfkit-10-4-migration-guide.md)
- [14 2 Migration Guide](/guides/ios/migration-guides/14-2-migration-guide.md)
- [Migrate to electronic signatures](/guides/ios/migration-guides/migrating-to-electronic-signatures.md)
- [Pspdfkit 11 5 Migration Guide](/guides/ios/migration-guides/pspdfkit-11-5-migration-guide.md)
- [Migrating From Apple Pdfkit](/guides/ios/migration-guides/migrating-from-apple-pdfkit.md)
- [Pspdfkit 10 Migration Guide](/guides/ios/migration-guides/pspdfkit-10-migration-guide.md)
- [Migrating To Advanced Digital Signatures Api](/guides/ios/migration-guides/migrating-to-advanced-digital-signatures-api.md)
- [Pspdfkit 10 3 Migration Guide](/guides/ios/migration-guides/pspdfkit-10-3-migration-guide.md)
- [Pspdfkit 11 3 Migration Guide](/guides/ios/migration-guides/pspdfkit-11-3-migration-guide.md)
- [Pspdfkit 12 2 Migration Guide](/guides/ios/migration-guides/pspdfkit-12-2-migration-guide.md)
- [Pspdfkit 13 Migration Guide](/guides/ios/migration-guides/pspdfkit-13-migration-guide.md)
- [Pspdfkit 13 3 Migration Guide](/guides/ios/migration-guides/pspdfkit-13-3-migration-guide.md)
- [Pspdfkit 12 3 Migration Guide](/guides/ios/migration-guides/pspdfkit-12-3-migration-guide.md)
- [Pspdfkit 12 Migration Guide](/guides/ios/migration-guides/pspdfkit-12-migration-guide.md)
- [Pspdfkit 5 Migration Guide](/guides/ios/migration-guides/pspdfkit-5-migration-guide.md)
- [Pspdfkit 3 Migration Guide](/guides/ios/migration-guides/pspdfkit-3-migration-guide.md)
- [Pspdfkit 4 Migration Guide](/guides/ios/migration-guides/pspdfkit-4-migration-guide.md)
- [Pspdfkit 11 4 Migration Guide](/guides/ios/migration-guides/pspdfkit-11-4-migration-guide.md)
- [Pspdfkit 6 5 Migration Guide](/guides/ios/migration-guides/pspdfkit-6-5-migration-guide.md)
- [Pspdfkit 7 6 Migration Guide](/guides/ios/migration-guides/pspdfkit-7-6-migration-guide.md)
- [Pspdfkit 9 2 Migration Guide](/guides/ios/migration-guides/pspdfkit-9-2-migration-guide.md)
- [Pspdfkit 6 Migration Guide](/guides/ios/migration-guides/pspdfkit-6-migration-guide.md)
- [PSPDFKit 8 migration guide for iOS developers](/guides/ios/migration-guides/pspdfkit-8-migration-guide.md)
- [Pspdfkit 9 4 Migration Guide](/guides/ios/migration-guides/pspdfkit-9-4-migration-guide.md)
- [Pspdfkit 9 3 Migration Guide](/guides/ios/migration-guides/pspdfkit-9-3-migration-guide.md)
- [Upgrading](/guides/ios/getting-started/upgrading.md)
- [Pspdfkit 9 Migration Guide](/guides/ios/migration-guides/pspdfkit-9-migration-guide.md)
- [Migrate to PSPDFKit 7 with ease](/guides/ios/migration-guides/pspdfkit-7-migration-guide.md)

