NSFilePresenter — е протокол Foundation, който позволява на обект да получава известия за промени на файлове и директории във файловата система на iOS и macOS. Класът имплементира методите на протокола и се регистрира чрез NSFileCoordinator, след което системата автоматично извиква тези методи при всяка операция с проследявания файл. Според Apple Developer Documentation (2025), NSFilePresenter се използва в приложения с многонишков достъп до документи за предотвратяване на конфликти при запис. Протоколът задължително се използва във връзка с NSFileCoordinator — само така се осигурява безопасна координация на достъпа.
Основни точки
NSFilePresenter — е протокол Foundation, предназначен за проследяване на промени на файлове и директории в операционните системи на Apple. Протоколът дефинира набор от методи, които обектът-наблюдател имплементира за получаване на известия за събития на файловата система.
Основната задача на протокола е да осигури безопасен достъп до файлове в многонишкови сценарии. В iOS и macOS множество процеси и нишки могат едновременно да имат достъп до един и същ файл чрез NSFileCoordinator, а NSFilePresenter гарантира, че всеки участник получава актуално състояние на данните.
Протоколът е включен във Foundation от iOS 5.0 и macOS 10.7. Използва се в приложения, работещи с документи, бази данни и всякакви файлове, които могат да бъдат променяни едновременно от различни източници — например при синхронизация чрез iCloud или при съвместно редактиране.
Документно-ориентирани приложения — основната област на използване на NSFilePresenter. Приложенията, работещи с UIDocument или NSDocument, автоматично се регистрират като презентери чрез NSFileCoordinator. Това позволява коректно обработване на конфликти при редактиране на един и същ файл от няколко прозореца или устройства.
iCloud синхронизация — вторият ключов сценарий. Когато файл се промени на едно устройство, iCloud го синхронизира на всички свързани устройства. 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, а презентерът трябва да актуализира референцията към файла. Без имплементация на този метод презентерът ще продължи да сочи към стария, несъществуващ път.
NSFileCoordinator и NSFilePresenter — неразделна двойка. NSFileCoordinator управлява достъпа до файлове и извиква методите на презентера. Презентерът не работи директно с файловата система — всички операции преминават през координатора, който гарантира атомарност на промените.
Координаторът регистрира презентера чрез метода addFilePresenter на класа NSFileCoordinator. След добавяне презентерът започва да получава известия. Премахването става чрез removeFilePresenter. Системата поддържа слаба референция към презентера, затова обектът трябва да бъде жив през целия период на проследяване.
Според Apple WWDC 2022, NSFileCoordinator използва механизъм за координация на ниво ядро, което осигурява минимално закъснение при блокировки. В най-новите версии на iOS координаторът е оптимизиран за работа с Sandbox и разширения на приложения.
Intention — всяка операция за четене или запис трябва да бъде обвита в блок за координация: четене чрез coordinateReadingItemAtURL, запис чрез coordinateWritingItemAtURL. Координаторът автоматично блокира файла за други участници по време на изпълнение на блока.
Пакетна координация — за операции с множество файлове се използва пакетна координация. Координаторът атомарно блокира всички посочени файлове, изпълнява операцията и премахва блокировките. Това е критично важно при преместване или копиране на набори от документи.
Нека създадем клас DocumentPresenter, който имплементира протокола NSFilePresenter и проследява промените на файла на документа. Класът съдържа референция към файла, вътрешни данни и флаг за актуалност.
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 |
Често задавани въпроси
NSFileHandle — е нискониво интерфейс за четене и запис на данни, който не предоставя механизми за уведомяване за промени от други процеси. NSFilePresenter работи на ниво координация: получава събития от системата при всяка промяна на файла, независимо от източника — друга нишка, процес или iCloud.
Да. NSFilePresenter няма смисъл без NSFileCoordinator. Презентерът само дефинира методите за обработка, докато координаторът управлява блокировките и извиква тези методи. Ако използвате NSFilePresenter без координатор, известията няма да бъдат доставяни.
Може, но с ограничения. Свойството presentedItemURL връща само един URL, затова за проследяване на множество файлове се използва протоколът NSFilePresenter с допълнителни методи за поделементи. Алтернатива — създаване на отделна инстанция на презентер за всеки файл.
NSFilePresenter е напълно съвместим с пясъчника на iOS. Приложението може да проследява само файлове в рамките на своя контейнер. За достъп до файлове на други приложения се използват App Groups или Security-Scoped Bookmark. Координаторът работи в рамките на разрешенията на пясъчника.
Използвайте debounce или throttle вътре в метода presentedItemDidChange. Създайте таймер със закъснение от 0,3-0,5 секунди и го нулирайте при всяко ново извикване. След стабилизиране изпълнете презареждане на данните. Това предотвратява многократната обработка на един и същ пакет промени.
Заключение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също