NSFileCoordinator — File Access Coordination in iOS

Author: IT Sectr Published: 2026-07-11 Reading time: 7 min

NSFileCoordinator is a Foundation class in iOS and macOS that ensures safe file access when multiple threads, processes, or extensions work simultaneously. According to Apple Developer Documentation, 2024, NSFileCoordinator prevents race conditions when reading and writing files, guaranteeing that no process reads data while another is modifying it. The coordinator is used in iCloud Drive, File Provider Extension, and any multithreaded file operations.

Key Takeaways

  • NSFileCoordinator — a class for safe file access from multiple threads and processes
  • Coordination intents (reading/writing intent) declare the operation type before execution
  • Race condition prevention — the coordinator's main task in parallel access
  • File Provider support — the coordinator is mandatory when working with iCloud Drive and extension files
  • NSFilePresenter — a protocol for receiving notifications about file changes from other processes

What Is NSFileCoordinator?

NSFileCoordinator is a file access synchronization mechanism at the operating system level, introduced by Apple in iOS 5 and macOS 10.7 Lion. Unlike traditional locks (NSLock, pthread_mutex), the coordinator works at the file system level and can coordinate access between different processes, not just between threads of the same application.

The need for NSFileCoordinator arises from the Sandbox architecture in iOS: each process (application, extension, system service) runs in an isolated environment with its own file access. When multiple processes try to read and write the same file simultaneously (e.g., during iCloud Drive synchronization), without a coordinator, race conditions occur: process A reads the file while process B has already partially overwritten it.

According to WWDC 2023, Apple strongly recommends using NSFileCoordinator for all file operations in the Ubiquity container (iCloud Drive) and when working with File Provider Extension. Ignoring coordination is one of the common causes of data corruption and non-reproducible bugs in iOS applications.

Types of Coordination Intents

Coordination Intent (NSFileCoordinator.ReadingIntent / WritingIntent) is an object that declares the type of operation a thread or process plans to perform. The coordinator uses these intents to determine access order and resolve conflicts.

Intent TypeDescriptionWhen to Use
ReadingIntentReading a file without modificationsOpening a document, loading data
WritingIntentWriting with possible content modificationSaving a document, editing
ReadingIntent(URL, options: .withoutChanges)Reading without change trackingQuick content preview
WritingIntent(URL, options: .contentIndependentMetadataOnly)Modifying metadata onlyUpdating date or attributes
WritingIntent(URL, options: .forDeleting)Deleting a fileUser document deletion

Coordination rules: multiple simultaneous reads are allowed (if there is no active write), writing is exclusive — no reads or writes are allowed during a write operation. This follows the readers-writer lock model, but with additional support for inter-process coordination through launchd and XPC.

Important nuance: NSFileCoordinator does not prevent file access via regular NSData or FileManager — it only coordinates operations that are explicitly wrapped in coordination blocks. If another thread accesses the file directly without the coordinator, the very race conditions that the coordinator is designed to prevent will occur.

NSFileCoordinator in Action: Code Examples

Basic pattern for using NSFileCoordinator consists of three steps: create a coordinator instance, declare an intent (read or write), and perform the operation inside a coordination block. The coordinator guarantees that no other coordinator will simultaneously work with the same file.

swift
import Foundation

let coordinator = NSFileCoordinator()
let fileURL = getDocumentURL()

// Safe reading
let readIntent = NSFileCoordinator
    .ReadingIntent(url: fileURL)
var content: Data?
var readError: NSError?

coordinator.coordinate(with: readIntent) { error in
    if let error = error {
        readError = error
        return
    }
    content = try? Data(contentsOf: fileURL)
}

// Safe writing
let writeIntent = NSFileCoordinator
    .WritingIntent(url: fileURL)

coordinator.coordinate(with: writeIntent) { error in
    guard error == nil else { return }
    do {
        try newData.write(to: fileURL)
    } catch {
        Logger.storage.error(
            "Write failed: \(error)"
        )
    }
}

Batch operation — the coordinator can handle multiple files in one operation using an array of intents. This is convenient for moving, copying, or deleting a set of files as a single transaction. If one of the intents cannot be fulfilled, the entire operation is cancelled with an error.

swift
let coordinator = NSFileCoordinator()
let readIntent = NSFileCoordinator
    .ReadingIntent(url: sourceURL)
let writeIntent = NSFileCoordinator
    .WritingIntent(url: destURL)

coordinator.coordinate(
    with: [readIntent, writeIntent]
) { error in
    try? FileManager.default
        .copyItem(at: sourceURL, to: destURL)
}

Asynchronous coordination — starting from iOS 15, NSFileCoordinator supports asynchronous methods with a completion handler, allowing coordination without blocking the calling thread. This is critical for the UI thread, where synchronous coordination waiting can cause interface freezing for seconds.

NSFilePresenter Protocol and Notifications

NSFilePresenter is a protocol that an object implements to receive notifications about changes to files coordinated by NSFileCoordinator. If your application displays the contents of a file that may be changed by another process (e.g., iCloud Drive syncs a new version), implementing NSFilePresenter allows you to update the interface in a timely manner.

swift
class DocumentPresenter: NSFilePresenter {
    let presentedItemURL: URL?
    let presentedItemOperationQueue: OperationQueue

    init(url: URL) {
        presentedItemURL = url
        presentedItemOperationQueue = OperationQueue()
    }

    func presentedItemDidChange() {
        DispatchQueue.main.async {
            NotificationCenter.default
                .post(name: .documentDidChange,
                      object: self)
        }
    }

    func presentedItemDidMove(to newURL: URL) {
        Logger.storage.info(
            "File moved to: \(newURL.lastPathComponent)"
        )
    }

    func accommodatePresentedItemDeletion(
        completionHandler: @escaping (Error?) -> Void
    ) {
        Logger.storage.warn("File deleted externally")
        completionHandler(nil)
    }
}

Protocol methods: presentedItemDidChange is called when file content changes, presentedItemDidMove(to:) — after file relocation, accommodatePresentedItemDeletion — before file deletion by another process (allows the application to close the file gracefully). Additionally, the protocol supports versioning through presentedItemDidGainVersion: and presentedItemDidLoseVersion:.

Important: NSFilePresenter must be registered in the system via NSFileCoordinator.addFilePresenter:. Without registration, notifications will not be delivered. Registration is performed once at application startup and does not require re-registration when the presenter is recreated.

Best Practices for File Coordination

Always use the coordinator for files in the Ubiquity container (iCloud Drive) and directories accessible to extensions. Even if the application is currently single-threaded, future updates or system changes may add parallel access, and the lack of coordination will lead to hard-to-find bugs.

Minimize time inside the coordination block. While the block is executing, other processes cannot access the file. Long operations inside the block (complex data processing, network requests) block the entire file access system. Perform only reading or writing of data inside the block, and handle processing outside of it.

Avoid deadlocks: do not call the coordinator from inside another coordinator's block for the same file — this will cause a mutual deadlock. Use batch operations (array of intents) instead of nested calls. If nesting is necessary, use different queues or different URLs.

According to objc.io (2024), typical errors when working with NSFileCoordinator include: missing error handling in the completion handler (leads to incomplete operations); coordinating only for writes but not for reads; using the outdated synchronous API on the UI thread; ignoring the NSFilePresenter protocol when working with iCloud Drive. The last error is the most insidious: the application displays outdated data without realizing the file has already been modified.

Frequently Asked Questions

What is NSFileCoordinator?

NSFileCoordinator is a Foundation class for safe file access from multiple threads or processes. It prevents race conditions by coordinating read and write operations at the file system level.

How is NSFileCoordinator different from NSLock?

NSLock works only within a single process (between threads). NSFileCoordinator coordinates access between different processes and extensions, including iCloud Drive synchronization and File Provider Extension.

Is it mandatory to use NSFileCoordinator for iCloud Drive?

Yes, Apple strongly recommends using NSFileCoordinator for all file operations in the Ubiquity container. Without the coordinator, data corruption can occur during synchronization between devices and conflicts with File Provider Extension.

What is NSFilePresenter?

NSFilePresenter is a protocol for receiving notifications about file changes. It allows the application to react to changes made by other processes: update the UI on modification, handle relocation, or prepare for file deletion.

What intent types does NSFileCoordinator support?

Five types: ReadingIntent (read), WritingIntent (write), ReadingIntent with .withoutChanges (read without tracking), WritingIntent with .contentIndependentMetadataOnly (metadata only), and WritingIntent with .forDeleting (deletion). Each defines the level of file access.

Summary

  • NSFileCoordinator — a system mechanism for safe file access from threads, processes, and extensions
  • Coordination intents (read/write) declare the operation type before execution
  • Reads are allowed in parallel, writes are exclusive (readers-writer model)
  • NSFilePresenter — a protocol for notifications about file changes from other processes
  • iCloud Drive and File Provider require mandatory coordination to prevent data corruption
  • Minimize time inside the coordination block — long operations block other processes' access
  • Deadlocks are prevented through batch operations and avoiding nested coordinator calls

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also