---
title: "iOS PDF editor API usage: Rotate, create, copy | Nutrient"
canonical_url: "https://www.nutrient.io/guides/ios/features/document-editor/"
md_url: "https://www.nutrient.io/guides/ios/features/document-editor.md"
last_updated: "2026-06-09T10:32:42.812Z"
description: "IOS PDF editor usage: Rotate, create, copy | Nutrient API documentation for Nutrient iOS SDK with methods, properties, and code examples."
---

# iOS PDF editor API usage

Document Editor is a Nutrient component comprised of a set of MVC classes. It provides you and your users with a whole host of page editing features, including: new page creation, page duplication, copying and pasting, reordering, rotation, deletion, and the creation of new documents from a subset of selected pages.

This guide describes how you can use the document editing API in your application. To learn about the built-in UI, see the [Document Editing UI](https://www.nutrient.io/guides/ios/features/document-editor-ui.md) guide.

## Class overview

In addition to a [comprehensive UI](https://www.nutrient.io/guides/ios/features/document-editor-ui.md), the Document Editor also comes with under-the-hood access to Document Editor model classes, which you can use to: perform document editing in code, extend the built-in document editing UI, or build an entirely custom document editing user interface.

Here’s an overview of classes you might need to access to perform document editing operations:

| Class                         | Description                                                         |
| ----------------------------- | ------------------------------------------------------------------- |
| [`PDFDocumentEditor`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumenteditor)       | Main class for performing all supported document editing operations |
| [`PDFEditingChange`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfeditingchange)        | Represents a change that was performed by [`PDFDocumentEditor`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumenteditor)   |
| [`PDFNewPageConfiguration`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfnewpageconfiguration) | Represents configuration options for newly created pages            |

## Editing

To begin document editing on a [`Document`](https://www.nutrient.io/api/ios/documentation/pspdfkit/document), you first need to create a [`PDFDocumentEditor`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumenteditor). This is done using the [`init?(document:)`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumenteditor/init(document:)) initializer. You can then perform document editing operations on the resulting Document Editor by invoking its various instance methods. Each document-mutating method returns an array of [`PDFEditingChange`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfeditingchange) objects, which you can use to update your user interface (if relevant). The change objects are also sent to all configured Document Editor delegates. If you’re inserting a new page, you’ll also have to create a [`PDFNewPageConfiguration`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfnewpageconfiguration) object that you then pass to the [`PDFDocumentEditor.addPages(in:with:)`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumenteditor/addpages(in:with:)) method.

The Document Editor keeps track of the performed operations and offers built-in undo/redo support. Checking the [`canUndo`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumenteditor/canundo) property is also a good way to determine if the Document Editor requires saving.

## Saving

When you’re done with the performed changes, you need to call one of the save methods to preserve your changes. You have two options available:

- [`save(completionBlock:)`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumenteditor/save(completionblock:)) — This method writes the updated PDF document to the same file path used by the source document, overwriting the source document in the process. The use of this method has some restrictions. The document needs to be in a writable directory and needs to be comprised of a single document provider. You can use the [`canSave`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumenteditor/cansave) property to determine if a save is possible. The method performs the save operation asynchronously and provides a reference to the updated document in its completion block. A save will clear all caches related to the previous document state to avoid any inconsistencies.

- [`save(toPath:withCompletionBlock:)`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumenteditor/save(topath:withcompletionblock:)) — This save method can be used to perform a Save As operation. In this case, the changed PDF document is written to the provided path (you need to make sure it is writable by the application). This method is also performed asynchronously. The completion block in this case returns a newly created document. This method is always available, regardless of the [`canSave`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumenteditor/cansave) state. Note, however, that if you use the [`save(toPath:withCompletionBlock:)`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumenteditor/save(topath:withcompletionblock:)) method to overwrite a document that’s currently loaded, you’ll need to explicitly handle unloading (or reloading) of that document, including clearing all caches. Failing to do so might result in caching issues and/or exceptions.

The changes performed on the Document Editor object aren’t reflected in the associated [`Document`](https://www.nutrient.io/api/ios/documentation/pspdfkit/document) until the changes get saved. Choosing to not save a Document Editor object is thus equivalent to discarding the performed changes.

## Usage example

Here’s an example that rotates the first two pages and inserts a new page at the front of the currently loaded document of a [`PDFViewController`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfviewcontroller):

### SWIFT

```swift

let document = self.document
guard let editor = PDFDocumentEditor(document: document) else { return }

// Rotate the first two pages 90 degrees.
editor.rotatePages([0, 1], rotation: 90)

// Add a new page as the first page.
let pageTemplate = PageTemplate(pageType:.tiledPatternPage, identifier:.grid5mm)
let newPageConfiguration = PDFNewPageConfiguration(pageTemplate: pageTemplate) {
    $0.pageSize = document.pageInfoForPage(at: 0)!.size
    $0.backgroundColor = UIColor(white: 0.95, alpha: 1)
}
editor.addPages(in: NSRange(location: 0, length: 1), with: newPageConfiguration)

// Save and overwrite the document.
editor.save { document, error in
    if let error = error {
        print("Document editing failed: \(error)")
        return
    }
    // Access the UI on the main thread.
    DispatchQueue.main.async {
        self.pdfController.reloadData()
    }
}

```

### OBJECTIVE-C

```objc

PSPDFDocument *document = self.document;
PSPDFDocumentEditor *editor = [[PSPDFDocumentEditor alloc] initWithDocument:document];
if (!editor) return;

// Rotate the first two pages 90 degrees.
[editor rotatePages:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 2)] rotation:90];

// Add a new page as the first page.
PSPDFPageTemplate *pageTemplate = [[PSPDFPageTemplate alloc] initWithPageType:PSPDFNewPageTypeTiledPatternPage identifier:PSPDFTemplateIdentifierGrid5mm];
PSPDFNewPageConfiguration *newPageConfiguration = [PSPDFNewPageConfiguration newPageConfigurationWithPageTemplate:pageTemplate builderBlock:^(PSPDFNewPageConfigurationBuilder *builder) {
    builder.pageSize = [document pageInfoForPageAtIndex:0].size;
    builder.backgroundColor = [UIColor colorWithWhite:0.95f alpha:1.f];
}];
[editor addPagesInRange:NSMakeRange(0, 1) withConfiguration:newPageConfiguration];

// Save and overwrite the document.
[editor saveWithCompletionBlock:^(PSPDFDocument *savedDocument, NSError *error) {
    if (error) {
        NSLog(@"Document editing failed: %@", error);
        return;
    }
    // Access the UI on the main thread.
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.pdfController reloadData];
    });
}];

```

### New document creation

The Document Editor API can also be used to create new PDF documents from scratch. To do so, initialize [`PDFDocumentEditor`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumenteditor) without a [`PDFViewController`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfviewcontroller). You can then use the regular [`PDFDocumentEditor`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumenteditor) API to add and modify pages. When done, save the new document to a location on the file system:

### SWIFT

```swift

guard let documentEditor = PDFDocumentEditor(document: nil) else { return }

// Add the first page. At least one is needed to be able to save the document.
let pageTemplate = PageTemplate(pageType:.emptyPage, identifier:.blank)
let newPageConfiguration = PDFNewPageConfiguration(pageTemplate: pageTemplate) {
    $0.pageSize = CGSize(width: 595, height: 842); // A4 in points
}
documentEditor.addPages(in: NSRange(location: 0, length: 1), with: newPageConfiguration)

// Save to a new PDF file.
documentEditor.save(toPath: saveToPath) { document, error in
    if let error = error {
        print("Error saving document. Error: \(error)")
    }
}

```

### OBJECTIVE-C

```objc

PSPDFDocumentEditor *documentEditor = [[PSPDFDocumentEditor alloc] init];
if (!documentEditor) return;

// Add the first page. At least one is needed to be able to save the document.
PSPDFPageTemplate *pageTemplate = [[PSPDFPageTemplate alloc] initWithPageType:PSPDFNewPageTypeTiledPatternPage identifier:PSPDFTemplateIdentifierGrid5mm];
PSPDFNewPageConfiguration *newPageConfiguration = [PSPDFNewPageConfiguration newPageConfigurationWithPageTemplate:pageTemplate builderBlock:^(PSPDFNewPageConfigurationBuilder *builder) {
    builder.pageSize = CGSizeMake(595, 842); // A4 in points
}];
[documentEditor addPagesInRange:NSMakeRange(0, 1) withConfiguration:newPageConfiguration];

// Save to a new PDF file.
[documentEditor saveToPath:saveToPath withCompletionBlock:^(PSPDFDocument *document, NSError *error) {
    if (error) {
        NSLog(@"Error saving document. Error: %@", error);
    }
}];

```

## Import and export

The [`PDFDocumentEditor`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumenteditor) API can also be used either to create a new document from a subset of the current document’s pages or to import pages from an outside document.

To export a set of pages, use [`PDFDocumentEditor.exportPages(_:toPath:withCompletionBlock:)`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumenteditor/exportpages(_:topath:withcompletionblock:)) and provide a destination path for the generated PDF. The method will write out a new PDF file and call the completion block when the operation finishes.

To import pages, call [`PDFDocumentEditor.importPages(to:from:withCompletionBlock:queue:)`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumenteditor/importpages(to:from:withcompletionblock:queue:)) This method takes a [`Document`](https://www.nutrient.io/api/ios/documentation/pspdfkit/document), which needs to be a `fileURL`-based document, and inserts all of its pages at the provided page index in the currently edited document. Just like with any other Document Editor operation, importing new pages doesn’t actually modify the edited document until saving; the Document Editor simply records a reference to the other document and its pages. To reliably save the imported pages, the imported document PDF data needs to be preserved until the editing session is saved. [`PDFDocumentEditor.importPages(to:from:withCompletionBlock:queue:)`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdfdocumenteditor/importpages(to:from:withcompletionblock:queue:)) handles this for you automatically.

The import and export methods are also used to implement [`PDFDocumentEditorToolbarController`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfdocumenteditortoolbarcontroller)-level copy and paste operations.

## Availability

Currently, not all [`Document`](https://www.nutrient.io/api/ios/documentation/pspdfkit/document)s can be edited using the Document Editor. At the moment, document editing is limited to PDFs that store all their annotations inside the PDF file. In practice, this means document editing is limited to [`Document`](https://www.nutrient.io/api/ios/documentation/pspdfkit/document)s that only use [`PDFFileAnnotationProvider`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdffileannotationprovider)s without external storage. [`PDFFileAnnotationProvider`](https://www.nutrient.io/api/ios/documentation/pspdfkit/pdffileannotationprovider) stores annotations externally if the document’s [`annotationSaveMode`](https://www.nutrient.io/api/ios/documentation/pspdfkit/document/annotationsavemode-swift.property) is set to [`.externalFile`](https://www.nutrient.io/api/ios/documentation/pspdfkit/document/annotationsavemode-swift.enum/externalfile) or if it’s set to [`.embeddedWithExternalFileAsFallback`](https://www.nutrient.io/api/ios/documentation/pspdfkit/document/annotationsavemode-swift.enum/embeddedwithexternalfileasfallback) (the default) in combination with a PDF located at a file path to which your application can’t write.

If you want to guarantee that document editing and annotating will always be possible for your documents, it’s recommended to always ensure that the documents you’re working with are located in a directory your app can write to (for instance, the app’s `Documents` directory) before loading them.

If you initialize the Document Editor with an unsupported document, initialization fails and the initializer returns `nil`.
---

## Related pages

- [Add and insert images into PDFs on iOS](/guides/ios/editor/add-image.md)
- [Add pages to PDF files on iOS](/guides/ios/editor/add-page.md)
- [How to attach files to PDFs on iOS](/guides/ios/editor/attach-a-file.md)
- [Customizing PDF editing permissions on iOS](/guides/ios/editor/document-permissions.md)
- [Edit text in PDFs on iOS](/guides/ios/editor/edit-text.md)
- [Merge multiple PDF files on iOS](/guides/ios/editor/merge-or-combine.md)
- [PDF editor library for iOS](/guides/ios/features/document-processing.md)
- [Split PDFs on iOS](/guides/ios/editor/split.md)
- [Adding watermarks to PDFs on iOS](/guides/ios/editor/watermark.md)

