---
title: "PDF document features"
canonical_url: "https://www.nutrient.io/guides/ios/features/document-features/"
md_url: "https://www.nutrient.io/guides/ios/features/document-features.md"
last_updated: "2026-06-18T03:06:48.935Z"
description: "Nutrient iOS SDK 7.4 introduced a new document features system. Its goals are to allow you to check if certain features are available."
---

[Nutrient iOS SDK 7.4](https://www.nutrient.io/blog/pspdfkit-ios-7-4/) introduced a new document features system. Its goals are to allow you to check if certain features are available, to get notified of changes, and to easily customize the availability of features yourself.

## Checking features

[`PDFDocumentFeatures`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumentfeatures) is the class you can access to check if a certain feature is currently available. [`PDFDocumentFeatures`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumentfeatures) is owned by `Document` and represents the availability of the document owning it. You can access the features through the [`features` property of `Document`](https://www.nutrient.io/api/ios/documentation/pspdfkit/document/features). The available features are declared in [`PDFDocumentFeaturesSource`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumentfeaturessource), a protocol containing a method for every feature defined in Nutrient. While the methods in this protocol are optional, [`PDFDocumentFeatures`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumentfeatures) guarantees to implement all of them so you can safely access them without checking their availability first.

## Observing features

When building UI components or other components that rely on the state of a feature, it is helpful to be notified when the state of a document changes. For example, a document can be unmodifiable while it is still being loaded, but later on it may allow modifications. When these state changes happen, [`PDFDocumentFeatures`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumentfeatures) notifies its observers.

Registering an observer is easy. Once registered, you get back an observer token, which you can then use to either make the observer bound to the lifetime of another object (i.e. let the observer automatically remove itself when the other object is deallocated) or explicitly unregister the observer:

### SWIFT

```swift

let observer = document.features.addObserver(forFeature: #selector(getter: PDFDocumentFeaturesSource.canEditBookmarks)) { [weak self] (value) in

    // Update UI.
}

// Make the observer unregister automatically as soon as `self` is deallocated.
observer.bind(toObjectLifetime: self)

```

### OBJECTIVE-C

```objc

id<PSPDFDocumentFeaturesObserver> observer = [document.features addObserverForFeature:PSPDFDocumentFeatureMake(canEditBookmarks) updateHandler:^(BOOL value) {
    // Update UI.
}];

// Make the observer unregister automatically as soon as `self` is deallocated.
[observer bindToObjectLifetime:self];

```

If you instead want to explicitly unregister the observer, you should hold on to the observer and call [`remove(_:)`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumentfeatures/remove(_:)-2k62t) on the document features instance you used to register the observer.

Make certain not to create any retain cycles if you remove your observer, whether automatically or manually, during deallocation of objects that are referenced in the update block.

## Customizing features

The features system also allows you to customize the availability of certain features. This is done by implementing your own [`PDFDocumentFeaturesSource`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumentfeaturessource). To customize features, simply make a class conform to [`PDFDocumentFeaturesSource`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumentfeaturessource). There is no need to implement all methods; you should only implement the ones you want to customize.

Note that the different sources (our internal ones and your custom ones) will all be evaluated, and the result will be combined through a `logical AND`, meaning you can only disable features that would otherwise be enabled. You cannot enable features that are disabled by other sources, because a disabled feature is usually the result of either a system limitation such as printing not being available on the current device, or the document that should store changes not being in a writable location. As soon as one source marks a feature as unavailable, the feature will not be available and its UI elements will be disabled by Nutrient.

After implementing your custom source, you need to add it to each document features instance. Note that each instance can only be in one source; you cannot reuse your source instances in multiple documents:

### SWIFT

```swift

let source = MySource()
document.features.add([source])

```

### OBJECTIVE-C

```objc

id<PSPDFDocumentFeaturesSource> source = [MySource new];
[document.features addSources:@[source]];

```

[`PDFDocumentFeatures`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumentfeatures) will cache the result of the sources. Therefore, it is important that you notify it about changes in your source. For this purpose, [`PDFDocumentFeaturesSource`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumentfeaturessource) has one required property: the back reference to the features object it is attached to. You can use this to call [`update()`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumentfeatures/update()) on it. This will let the document features object know to check its sources again and report any changes to registered observers. One way to do this is to call [`update()`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumentfeatures/update()) whenever the setter of one of your properties is changed. Of course, this depends on how your source behaves internally:

### SWIFT

```swift

var canEditBookmarks: Bool {
    didSet {
        features?.update()
    }
}

```

### OBJECTIVE-C

```objc

- (void)setCanEditBookmarks:(BOOL)canEditBookmarks {
    _canEditBookmarks = canEditBookmarks;
    [self.features updateFeatures];
}

```

See [`DisableBookmarkEditingExample.swift`](https://github.com/PSPDFKit/pspdfkit-ios-catalog/blob/master/Catalog/Examples/Subclassing/DisableBookmarkEditingExample.swift) in [Nutrient Catalog](https://www.nutrient.io/guides/ios/getting-started/example-projects.md#nutrient-catalog) for more details.
---

## Related pages

- [Adding Auxiliary Or Decorative Views](/guides/ios/customizing-pdf-pages/adding-auxiliary-or-decorative-views.md)
- [Adding Custom Views To A Page](/guides/ios/customizing-pdf-pages/adding-custom-views-to-a-page.md)
- [Options to disable or enable PDF editing on iOS](/guides/ios/features/controlling-pdf-editing.md)
- [Document Downloads](/guides/ios/miscellaneous/document-downloads.md)
- [SwiftUI PDF library](/guides/ios/getting-started/swiftui.md)
- [Configure document sharing options on iOS](/guides/ios/miscellaneous/document-sharing.md)

