NSFilePresenter: какво е, протокол NSFileCoordinator и методи за проследяване

Автор: IT Sectr Публикувано: 2026-07-12 Време за четене: 7 мин

NSFilePresenter — е протокол Foundation, който позволява на обект да получава известия за промени на файлове и директории във файловата система на iOS и macOS. Класът имплементира методите на протокола и се регистрира чрез NSFileCoordinator, след което системата автоматично извиква тези методи при всяка операция с проследявания файл. Според Apple Developer Documentation (2025), NSFilePresenter се използва в приложения с многонишков достъп до документи за предотвратяване на конфликти при запис. Протоколът задължително се използва във връзка с NSFileCoordinator — само така се осигурява безопасна координация на достъпа.

Основни точки

  • NSFilePresenter — протокол Foundation за проследяване на промени на файлове и директории в iOS и macOS.
  • NSFileCoordinator — задължителен партньорски клас, който управлява достъпа и извиква методите на делегата.
  • accommodatePresentedItemDeletion — метод за обработка на изтриване на проследяван файл с възможност за отказ.
  • presentedItemDidChange — извиква се при всяка промяна на съдържанието на файла или директорията.
  • presentedItemURL — задължително свойство, връщащо URL на проследявания файл.

Какво е NSFilePresenter?

NSFilePresenter — е протокол Foundation, предназначен за проследяване на промени на файлове и директории в операционните системи на Apple. Протоколът дефинира набор от методи, които обектът-наблюдател имплементира за получаване на известия за събития на файловата система.

Основната задача на протокола е да осигури безопасен достъп до файлове в многонишкови сценарии. В iOS и macOS множество процеси и нишки могат едновременно да имат достъп до един и същ файл чрез NSFileCoordinator, а NSFilePresenter гарантира, че всеки участник получава актуално състояние на данните.

Протоколът е включен във Foundation от iOS 5.0 и macOS 10.7. Използва се в приложения, работещи с документи, бази данни и всякакви файлове, които могат да бъдат променяни едновременно от различни източници — например при синхронизация чрез iCloud или при съвместно редактиране.

Къде се използва NSFilePresenter

Документно-ориентирани приложения — основната област на използване на NSFilePresenter. Приложенията, работещи с UIDocument или NSDocument, автоматично се регистрират като презентери чрез NSFileCoordinator. Това позволява коректно обработване на конфликти при редактиране на един и същ файл от няколко прозореца или устройства.

iCloud синхронизация — вторият ключов сценарий. Когато файл се промени на едно устройство, iCloud го синхронизира на всички свързани устройства. NSFilePresenter уведомява приложението за тези промени, позволявайки своевременно обновяване на интерфейса.

Многонишкови редактори — третият сценарий. В приложения, където фонови опашки зареждат и запазват данни едновременно с работата на потребителя, NSFilePresenter предотвратява състояния на състезание при запис и четене на файлове.

Как работи NSFilePresenter?

Механизъм на работа NSFilePresenter се основава на модела на делегиране: обектът имплементира методите на протокола, регистрира се чрез NSFileCoordinator и получава извиквания при всяка промяна на проследявания файл. Системата сама определя кога е настъпила промяна и кои методи трябва да бъдат извикани.

Процесът започва с това, че обектът създава инстанция на NSFileCoordinator и извиква метода на координатора, предавайки URL на файла. Координаторът проверява дали за този URL са регистрирани някакви презентери. Ако да, блокира достъпа за четене или запис и уведомява презентерите за предстоящата промяна чрез методите на протокола.

След завършване на операцията координаторът премахва блокировката и извиква финалните известия. Важно е, че презентерът не управлява потока на изпълнение — той само реагира на събития. За координацията изцяло отговаря NSFileCoordinator.

Жизнен цикъл на известието

Фаза на подготовка — преди изпълнение на операцията координаторът извиква метода accommodatePresentedItemDeletion или accommodatePresentedSubitemDeletion. Презентерът може да обработи ситуацията или да отмени операцията, връщайки грешка. Тази фаза позволява на приложението коректно да приключи работа с файла преди неговата промяна.

Фаза на известие — след завършване на операцията координаторът извиква presentedItemDidChange или presentedSubitemDidChange. Презентерът получава сигнал, че файлът се е променил, и може да прочете отново съдържанието му. За преместване на файл се извиква presentedItemDidMoveToURL с новата локация.

Фаза на завършване — координаторът премахва всички блокировки и освобождава ресурси. Презентерът може да продължи работа с актуализираните данни. И трите фази се изпълняват синхронно в една нишка, затова методите на протокола трябва да работят бързо, без дълги входно-изходни операции.

Основни методи на протокола

Протоколът NSFilePresenter съдържа няколко задължителни и опционални метода. Единственото задължително свойство е presentedItemURL, връщащо URL на проследявания файл или директория. Без това свойство обектът не може да бъде регистриран като презентер.

Задължителни методи

presentedItemURL — свойство от тип URL?, което трябва да върне пътя до проследявания файл. Ако обектът проследява множество файлове, свойството връща URL на основния елемент. За директории се връща URL на самата директория.

presentedItemDidChange — извиква се след промяна на съдържанието на проследявания файл. В този метод презентерът актуализира вътрешното си състояние и презарежда данните. Този метод не получава информация какво точно се е променило — само факта на промяната.

Опционални методи

accommodatePresentedItemDeletion — извиква се преди изтриване на файл. Презентерът може да запази текущото състояние, да затвори файлови дескриптори или да отмени операцията, връщайки NSError. Ако методът върне грешка, операцията по изтриване не се изпълнява.

presentedItemDidMoveToURL — извиква се след преместване или преименуване на файл. Методът получава новия URL, а презентерът трябва да актуализира референцията към файла. Без имплементация на този метод презентерът ще продължи да сочи към стария, несъществуващ път.

NSFilePresenter и NSFileCoordinator

NSFileCoordinator и NSFilePresenter — неразделна двойка. NSFileCoordinator управлява достъпа до файлове и извиква методите на презентера. Презентерът не работи директно с файловата система — всички операции преминават през координатора, който гарантира атомарност на промените.

Координаторът регистрира презентера чрез метода addFilePresenter на класа NSFileCoordinator. След добавяне презентерът започва да получава известия. Премахването става чрез removeFilePresenter. Системата поддържа слаба референция към презентера, затова обектът трябва да бъде жив през целия период на проследяване.

Според Apple WWDC 2022, NSFileCoordinator използва механизъм за координация на ниво ядро, което осигурява минимално закъснение при блокировки. В най-новите версии на iOS координаторът е оптимизиран за работа с Sandbox и разширения на приложения.

Правила за координация

Intention — всяка операция за четене или запис трябва да бъде обвита в блок за координация: четене чрез coordinateReadingItemAtURL, запис чрез coordinateWritingItemAtURL. Координаторът автоматично блокира файла за други участници по време на изпълнение на блока.

Пакетна координация — за операции с множество файлове се използва пакетна координация. Координаторът атомарно блокира всички посочени файлове, изпълнява операцията и премахва блокировките. Това е критично важно при преместване или копиране на набори от документи.

Пример за имплементация на NSFilePresenter

Нека създадем клас DocumentPresenter, който имплементира протокола NSFilePresenter и проследява промените на файла на документа. Класът съдържа референция към файла, вътрешни данни и флаг за актуалност.

swift
import Foundation

class DocumentPresenter: NSObject, NSFilePresenter {
    var presentedItemURL: URL? {
        return self.fileURL
    }

    var presentedItemOperationQueue: OperationQueue {
        return self.queue
    }

    private let fileURL: URL
    private let queue = OperationQueue()

    func presentedItemDidChange() {
        self.reloadData()
    }

    func accommodatePresentedItemDeletion() throws {
        try self.saveCurrentState()
    }

    private func reloadData() {
        let coordinator = NSFileCoordinator(filePresenter: self)
        var error: NSError?
        coordinator.coordinate(readingItemAt: self.fileURL,
                               options: [],
                               error: &error)
        { readURL in
            guard let data = try? Data(contentsOf: readURL)
            else { return }
            self.processData(data)
        }
    }

    private func processData(_: Data) {
        // Обработка на данни на документа
    }
}

Класът имплементира presentedItemDidChange за презареждане на данни при промяна на файла и accommodatePresentedItemDeletion за запазване на състоянието преди изтриване. Операционната опашка гарантира, че всички известия се обработват последователно.

Регистрацията на презентера се извършва чрез NSFileCoordinator.addFilePresenter при отваряне на документа. Важно е да се предадат правилните опции за четене на координатора — withoutChanges за операции без промяна или immediatelyAvailable за сценарии с незабавен достъп.

Типични грешки при работа

Първата често срещана грешка — липса на имплементация на presentedItemOperationQueue. Ако не посочите опашка, известията могат да идват в произволна нишка, причинявайки състезание на данните. Винаги използвайте последователна OperationQueue за обработка на известия.

Втората грешка — блокиране в методите на презентера. Методите на протокола се извикват синхронно от координатора. Ако презентерът изпълнява дълга операция (запис в база данни, мрежова заявка), той блокира координатора за всички останали участници. Преместете тежките операции във фонови опашки.

Третата грешка — игнориране на accommodatePresentedItemDeletion. Ако презентерът не имплементира този метод и не връща грешка, файлът може да бъде изтрит без запазване на текущото състояние. Винаги запазвайте данни в този метод, ако все още не са записани на диска.

Четвъртата грешка — циклична координация. Когато презентерът вътре в метода на известие отново извика координатора за същия файл, възниква deadlock. Проверете флага isCoordinatedOperation преди да започнете координация вътре в handler-а.

ГрешкаПоследицаРешение
Няма опашка от операцииСъстезание на данни в многонишковостПосочете OperationQueue
Блокиране в методитеЗависване на координатораПреместете във фонова нишка
Игнориране на deletionЗагуба на данни при изтриванеИмплементирайте запазване
Циклична координацияDeadlock на приложениетоФлаг isCoordinatedOperation

Често задавани въпроси

Защо е необходим NSFilePresenter, ако съществува NSFileHandle?

NSFileHandle — е нискониво интерфейс за четене и запис на данни, който не предоставя механизми за уведомяване за промени от други процеси. NSFilePresenter работи на ниво координация: получава събития от системата при всяка промяна на файла, независимо от източника — друга нишка, процес или iCloud.

Задължително ли е използването на NSFileCoordinator с NSFilePresenter?

Да. NSFilePresenter няма смисъл без NSFileCoordinator. Презентерът само дефинира методите за обработка, докато координаторът управлява блокировките и извиква тези методи. Ако използвате NSFilePresenter без координатор, известията няма да бъдат доставяни.

Може ли един обект да бъде презентер за множество файлове?

Може, но с ограничения. Свойството presentedItemURL връща само един URL, затова за проследяване на множество файлове се използва протоколът NSFilePresenter с допълнителни методи за поделементи. Алтернатива — създаване на отделна инстанция на презентер за всеки файл.

Как NSFilePresenter работи с Sandbox в iOS?

NSFilePresenter е напълно съвместим с пясъчника на iOS. Приложението може да проследява само файлове в рамките на своя контейнер. За достъп до файлове на други приложения се използват App Groups или Security-Scoped Bookmark. Координаторът работи в рамките на разрешенията на пясъчника.

Какво да направите, ако presentedItemDidChange се извиква твърде често?

Използвайте debounce или throttle вътре в метода presentedItemDidChange. Създайте таймер със закъснение от 0,3-0,5 секунди и го нулирайте при всяко ново извикване. След стабилизиране изпълнете презареждане на данните. Това предотвратява многократната обработка на един и същ пакет промени.

Заключение

  • NSFilePresenter — протокол Foundation за получаване на известия за промени на файлове в iOS и macOS, работещ изключително във връзка с NSFileCoordinator.
  • Задължително свойство presentedItemURL — без него обектът не може да бъде регистриран като презентер и няма да получава известия.
  • Основен метод presentedItemDidChange се извиква след всяка промяна на съдържанието на файла — използвайте го за презареждане на данни.
  • accommodatePresentedItemDeletion позволява коректно обработване на изтриване на файл и запазване на текущото състояние на приложението.
  • NSFileCoordinator управлява блокировките и гарантира атомарност на операциите — без координатор презентерът е безполезен.
  • Типични грешки включват липса на опашка от операции, блокиране в методите и циклична координация — важно е да ги избягвате чрез проектиране.
  • Debounce presentedItemDidChange при чести извиквания — използвайте таймер за групиране на промените преди презареждане.

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също