NSFilePresenter — to protokół Foundation, który pozwala obiektowi otrzymywać powiadomienia o zmianach plików i katalogów w systemie plików iOS i macOS. Klasa implementuje metody protokołu i rejestruje się przez NSFileCoordinator, po czym system automatycznie wywołuje te metody przy każdej operacji na śledzonym pliku. Według Apple Developer Documentation (2025), NSFilePresenter jest stosowany w aplikacjach z wielowątkowym dostępem do dokumentów w celu zapobiegania konfliktom zapisu. Protokół jest obowiązkowo używany w parze z NSFileCoordinator — tylko w ten sposób zapewnione jest bezpieczne koordynowanie dostępu.
Najważniejsze
NSFilePresenter — to protokół Foundation przeznaczony do śledzenia zmian plików i katalogów w systemach operacyjnych Apple. Protokół określa zestaw metod, które obiekt-obserwator implementuje, aby otrzymywać powiadomienia o zdarzeniach systemu plików.
Głównym zadaniem protokołu jest zapewnienie bezpiecznego dostępu do plików w scenariuszach wielowątkowych. W iOS i macOS wiele procesów i wątków może jednocześnie uzyskiwać dostęp do tego samego pliku przez NSFileCoordinator, a NSFilePresenter gwarantuje, że każdy uczestnik otrzymuje aktualny stan danych.
Protokół jest zawarty w Foundation od iOS 5.0 i macOS 10.7. Jest stosowany w aplikacjach pracujących z dokumentami, bazami danych i wszelkimi plikami, które mogą być zmieniane jednocześnie z różnych źródeł — na przykład podczas synchronizacji przez iCloud lub wspólnego edytowania.
Aplikacje zorientowane na dokumenty — główny obszar zastosowania NSFilePresenter. Aplikacje pracujące z UIDocument lub NSDocument automatycznie rejestrują się jako prezenterzy przez NSFileCoordinator. Pozwala to poprawnie obsługiwać konflikty podczas edytowania jednego pliku z wielu okien lub urządzeń.
Synchronizacja iCloud — drugi kluczowy scenariusz. Gdy plik zmienia się na jednym urządzeniu, iCloud synchronizuje go na wszystkich podłączonych urządzeniach. NSFilePresenter powiadamia aplikację o tych zmianach, umożliwiając terminową aktualizację interfejsu.
Edytory wielowątkowe — trzeci scenariusz. W aplikacjach, gdzie kolejki tła ładują i zapisują dane jednocześnie z pracą użytkownika, NSFilePresenter zapobiega stanom wyścigu przy zapisie i odczycie plików.
Mechanizm działania NSFilePresenter opiera się na modelu delegowania: obiekt implementuje metody protokołu, rejestruje się przez NSFileCoordinator i otrzymuje wywołania przy każdej zmianie śledzonego pliku. System sam określa, kiedy nastąpiła zmiana i które metody należy wywołać.
Proces rozpoczyna się od utworzenia przez obiekt instancji NSFileCoordinator i wywołania metody koordynatora z przekazaniem URL pliku. Koordynator sprawdza, czy dla tego URL zarejestrowani są jacyś prezenterzy. Jeśli tak, blokuje dostęp do odczytu lub zapisu i powiadamia prezenterów o nadchodzącej zmianie przez metody protokołu.
Po zakończeniu operacji koordynator zdejmuje blokadę i wywołuje końcowe powiadomienia. Ważne, że prezenter nie zarządza przepływem wykonania — tylko reaguje na zdarzenia. Za koordynację w pełni odpowiada NSFileCoordinator.
Faza przygotowania — przed wykonaniem operacji koordynator wywołuje metodę accommodatePresentedItemDeletion lub accommodatePresentedSubitemDeletion. Prezenter może obsłużyć sytuację lub anulować operację, zwracając błąd. Ta faza pozwala aplikacji poprawnie zakończyć pracę z plikiem przed jego zmianą.
Faza powiadomienia — po zakończeniu operacji koordynator wywołuje presentedItemDidChange lub presentedSubitemDidChange. Prezenter otrzymuje sygnał, że plik się zmienił, i może ponownie odczytać jego zawartość. Dla przeniesienia pliku wywoływana jest presentedItemDidMoveToURL z nową lokalizacją.
Faza zakończenia — koordynator zdejmuje wszystkie blokady i zwalnia zasoby. Prezenter może kontynuować pracę ze zaktualizowanymi danymi. Wszystkie trzy fazy są wykonywane synchronicznie w jednym wątku, dlatego metody protokołu muszą działać szybko, bez długotrwałych operacji wejścia-wyjścia.
Protokół NSFilePresenter zawiera kilka obowiązkowych i opcjonalnych metod. Jedyną obowiązkową właściwością jest presentedItemURL, zwracająca URL śledzonego pliku lub katalogu. Bez tej właściwości obiekt nie może być zarejestrowany jako prezenter.
presentedItemURL — właściwość typu URL?, która musi zwracać ścieżkę do śledzonego pliku. Jeśli obiekt śledzi wiele plików, właściwość zwraca URL głównego elementu. Dla katalogów zwracany jest URL samego katalogu.
presentedItemDidChange — wywoływana po zmianie zawartości śledzonego pliku. W tej metodzie prezenter aktualizuje swój stan wewnętrzny i przeładowuje dane. Ta metoda nie otrzymuje informacji o tym, co dokładnie się zmieniło — tylko fakt zmiany.
accommodatePresentedItemDeletion — wywoływana przed usunięciem pliku. Prezenter może zapisać bieżący stan, zamknąć deskryptory plików lub anulować operację, zwracając NSError. Jeśli metoda zwróci błąd, operacja usunięcia nie zostanie wykonana.
presentedItemDidMoveToURL — wywoływana po przeniesieniu lub zmianie nazwy pliku. Metoda otrzymuje nowy URL, a prezenter musi zaktualizować referencję do pliku. Bez implementacji tej metody prezenter będzie nadal wskazywał starą, nieistniejącą ścieżkę.
NSFileCoordinator i NSFilePresenter — nierozłączna para. NSFileCoordinator zarządza dostępem do plików i wywołuje metody prezentera. Prezenter nie pracuje bezpośrednio z systemem plików — wszystkie operacje przechodzą przez koordynatora, który gwarantuje atomowość zmian.
Koordynator rejestruje prezentera przez metodę addFilePresenter klasy NSFileCoordinator. Po dodaniu prezenter zaczyna otrzymywać powiadomienia. Usunięcie następuje przez removeFilePresenter. System przechowuje słabą referencję do prezentera, dlatego obiekt musi być żywy przez cały okres śledzenia.
Według Apple WWDC 2022, NSFileCoordinator używa mechanizmu koordynacji na poziomie jądra, co zapewnia minimalne opóźnienie przy blokadach. W najnowszych wersjach iOS koordynator jest zoptymalizowany do pracy z Sandbox i rozszerzeniami aplikacji.
Intention — każda operacja odczytu lub zapisu musi być owinięta w blok koordynacji: odczyt przez coordinateReadingItemAtURL, zapis przez coordinateWritingItemAtURL. Koordynator automatycznie blokuje plik dla innych uczestników na czas wykonania bloku.
Batch coordination — dla operacji na wielu plikach stosuje się koordynację wsadową. Koordynator atomowo blokuje wszystkie wskazane pliki, wykonuje operację i zdejmuje blokady. Jest to krytycznie ważne przy przenoszeniu lub kopiowaniu zestawów dokumentów.
Stwórzmy klasę DocumentPresenter, która implementuje protokół NSFilePresenter i śledzi zmiany pliku dokumentu. Klasa zawiera referencję do pliku, dane wewnętrzne i flagę aktualności.
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) {
// Przetwarzanie danych dokumentu
}
}
Klasa implementuje presentedItemDidChange do przeładowania danych przy zmianie pliku oraz accommodatePresentedItemDeletion do zapisania stanu przed usunięciem. Kolejka operacyjna gwarantuje, że wszystkie powiadomienia są przetwarzane sekwencyjnie.
Rejestracja prezentera odbywa się przez NSFileCoordinator.addFilePresenter przy otwieraniu dokumentu. Ważne jest przekazanie koordynatorowi poprawnych opcji odczytu — withoutChanges dla operacji bez modyfikacji lub immediatelyAvailable dla scenariuszy z natychmiastowym dostępem.
Pierwszym częstym błędem jest brak implementacji presentedItemOperationQueue. Jeśli nie określisz kolejki, powiadomienia mogą przychodzić w dowolnym wątku, powodując wyścig danych. Zawsze używaj sekwencyjnej OperationQueue do obsługi powiadomień.
Drugim błędem jest blokowanie w metodach prezentera. Metody protokołu są wywoływane synchronicznie z koordynatora. Jeśli prezenter wykonuje długotrwałą operację (zapis do bazy danych, żądanie sieciowe), blokuje koordynatora dla wszystkich pozostałych uczestników. Przenoś ciężkie operacje do kolejek tła.
Trzecim błędem jest ignorowanie accommodatePresentedItemDeletion. Jeśli prezenter nie implementuje tej metody i nie zwraca błędu, plik może zostać usunięty bez zapisania bieżącego stanu. Zawsze zapisuj dane w tej metodzie, jeśli nie zostały jeszcze zapisane na dysk.
Czwartym błędem jest koordynacja cykliczna. Gdy prezenter wewnątrz metody powiadomienia ponownie wywołuje koordynatora dla tego samego pliku, powstaje deadlock. Sprawdzaj flagę isCoordinatedOperation przed uruchomieniem koordynacji wewnątrz handlera.
| Błąd | Konsekwencja | Rozwiązanie |
|---|---|---|
| Brak kolejki operacji | Wyścig danych w wielowątkowości | Określić OperationQueue |
| Blokowanie w metodach | Zawieszenie koordynatora | Przenieść do wątku tła |
| Ignorowanie deletion | Utrata danych przy usunięciu | Zaimplementować zapis |
| Koordynacja cykliczna | Deadlock aplikacji | Flaga isCoordinatedOperation |
Często zadawane pytania
NSFileHandle — to niskopoziomowy interfejs do odczytu i zapisu danych, który nie zapewnia mechanizmów powiadamiania o zmianach z innych procesów. NSFilePresenter działa na poziomie koordynacji: otrzymuje zdarzenia od systemu przy każdej zmianie pliku, niezależnie od źródła — inny wątek, proces lub iCloud.
Tak. NSFilePresenter nie ma sensu bez NSFileCoordinator. Prezenter tylko określa metody obsługi, a koordynator zarządza blokadami i wywołuje te metody. Jeśli używasz NSFilePresenter bez koordynatora, powiadomienia nie będą dostarczane.
Może, ale z ograniczeniami. Właściwość presentedItemURL zwraca tylko jeden URL, dlatego do śledzenia wielu plików używa się protokołu NSFilePresenter z dodatkowymi metodami dla subelementów. Alternatywą jest utworzenie osobnej instancji prezentera dla każdego pliku.
NSFilePresenter jest w pełni kompatybilny z piaskownicą iOS. Aplikacja może śledzić pliki tylko wewnątrz swojego kontenera. Do dostępu do plików innych aplikacji używa się App Groups lub Security-Scoped Bookmark. Koordynator działa w ramach uprawnień piaskownicy.
Użyj debouce'a lub throttla wewnątrz metody presentedItemDidChange. Utwórz timer z opóźnieniem 0,3-0,5 sekundy i resetuj go przy każdym nowym wywołaniu. Po stabilizacji wykonaj przeładowanie danych. Zapobiega to wielokrotnemu przetwarzaniu jednego pakietu zmian.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również