NSFileCoordinator је Foundation класа у iOS и macOS која обезбеђује сигуран приступ датотекама при истовременом раду више нити, процеса или екстензија. Према Apple Developer Documentation, 2024, NSFileCoordinator спречава race conditions при читању и писању датотека, гарантујући да ниједан процес не чита податке у тренутку њихове измене од стране другог. Координатор се користи у iCloud Drive, File Provider Extension и свим више нитним операцијама са датотекама.
Главно
NSFileCoordinator — је механизам синхронизације приступа датотекама на нивоу оперативног система, представљен од стране Apple у iOS 5 и macOS 10.7 Lion. За разлику од традиционалних закључавања (NSLock, pthread_mutex), координатор ради на нивоу система датотека и може да координише приступ између различитих процеса, а не само између нити једне апликације.
Потреба за NSFileCoordinator произилази из Sandbox архитектуре у iOS: сваки процес (апликација, екстензија, системски сервис) ради у изолованом окружењу са сопственим приступом датотекама. Када више процеса покушава истовремено да чита и пише исту датотеку (на пример, при синхронизацији iCloud Drive), без координатора настају race conditions: процес А чита датотеку у тренутку када ју је процес Б већ делимично преписао.
Према WWDC 2023, Apple снажно препоручује коришћење NSFileCoordinator за све операције са датотекама у Ubiquity контејнеру (iCloud Drive) и при раду са File Provider Extension. Игнорисање координације је један од честих узрока оштећења података и непоновљивих грешака у iOS апликацијама.
Координациона намера (NSFileCoordinator.ReadingIntent / WritingIntent) — је објекат који декларише тип операције коју нит или процес планира да изврши. Координатор користи ове намере за одређивање редоследа приступа и решавање конфликата.
| Тип намере | Опис | Када користити |
|---|---|---|
| ReadingIntent | Читање датотеке без измена | Отварање документа, учитавање података |
| WritingIntent | Писање са могућом изменом садржаја | Чување документа, уређивање |
| ReadingIntent(URL, options: .withoutChanges) | Читање без праћења измена | Брзи преглед садржаја |
| WritingIntent(URL, options: .contentIndependentMetadataOnly) | Измена само метаподатака | Ажурирање датума или атрибута |
| WritingIntent(URL, options: .forDeleting) | Брисање датотеке | Брисање документа од стране корисника |
Правила координације: више истовремених читања је дозвољено (ако нема активног писања), писање је ексклузивно — ниједно читање или писање није дозвољено током операције писања. Ово одговара readers-writer lock моделу, али са додатном подршком за међупроцесну координацију преко launchd и XPC.
Важна нијанса: NSFileCoordinator не спречава приступ датотеци путем обичног NSData или FileManager — координише само оне операције које су експлицитно умотане у координационе блокове. Ако друга нит приступа датотеци директно, заобилазећи координатора, настају управо оне race conditions које координатор треба да спречи.
Основни образац коришћења NSFileCoordinator састоји се од три корака: креирање инстанце координатора, декларисање намере (читање или писање) и извршење операције унутар координационог блока. Координатор гарантује да ниједан други координатор неће истовремено радити са истом датотеком.
import Foundation
let coordinator = NSFileCoordinator()
let fileURL = getDocumentURL()
// Безбедно читање
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)
}
// Безбедно писање
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)"
)
}
}
Групна операција — координатор може да обрађује више датотека у једној операцији користећи низ намера. Ово је згодно за премештање, копирање или брисање скупа датотека као јединствене трансакције. Ако се једна од намера не може извршити, цела операција се отказује са грешком.
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)
}
Асинхрона координација — од iOS 15, NSFileCoordinator подржава асинхроне методе са completion handler-ом, што омогућава извршење координације без блокирања позивајуће нити. Ово је критично важно за UI нит, где синхроно чекање на координацију може изазвати замрзавање интерфејса на секунде.
NSFilePresenter — је протокол који објекат имплементира за примање обавештења о променама датотека које координише NSFileCoordinator. Ако ваша апликација приказује садржај датотеке коју може изменити други процес (на пример, iCloud Drive синхронизује нову верзију), имплементација NSFilePresenter омогућава благовремено ажурирање интерфејса.
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)
}
}
Методе протокола: presentedItemDidChange се позива при промени садржаја датотеке, presentedItemDidMove(to:) — након премештања датотеке, accommodatePresentedItemDeletion — пре брисања датотеке од стране другог процеса (омогућава апликацији да правилно затвори датотеку). Додатно, протокол подржава верзионисање кроз presentedItemDidGainVersion: и presentedItemDidLoseVersion:.
Важно: NSFilePresenter мора бити регистрован у систему преко NSFileCoordinator.addFilePresenter:. Без регистрације, обавештења неће бити достављена. Регистрација се врши једном при покретању апликације и не захтева поновну регистрацију при поновном креирању презентера.
Увек користите координатора за датотеке у Ubiquity контејнеру (iCloud Drive) и директоријумима доступним екстензијама. Чак и ако је апликација тренутно једнонитна, будућа ажурирања или системске промене могу додати паралелни приступ, а недостатак координације ће довести до тешко ухватљивих грешака.
Минимизирајте време у координационом блоку. Док се блок извршава, други процеси не могу приступити датотеци. Дуге операције унутар блока (сложена обрада података, мрежни захтеви) блокирају цео систем приступа датотекама. Обављајте само читање или писање података унутар блока, а обраду — ван њега.
Избегавајте deadlock-ове: не позивајте координатора из унутрашњости блока другог координатора за исту датотеку — то ће довести до међусобног блокирања. Користите групне операције (низ намера) уместо угнежђених позива. Ако је угнежђење неопходно, користите различите редове или различите URL-ове.
Према objc.io (2024), типичне грешке при раду са NSFileCoordinator укључују: изостанак обраде грешака у completion handler-у (доводи до незавршених операција); координација само за писање, али не и за читање; коришћење застарелог синхроног API-ја у UI нити; игнорисање NSFilePresenter протокола при раду са iCloud Drive. Последња грешка је најподмуклија: апликација приказује застареле податке не знајући да је датотека већ измењена.
Често постављана питања
NSFileCoordinator — Foundation класа за безбедан приступ датотекама из више нити или процеса. Спречава race conditions, координишући операције читања и писања на нивоу система датотека.
NSLock ради само унутар једног процеса (између нити). NSFileCoordinator координише приступ између различитих процеса и екстензија, укључујући iCloud Drive синхронизацију и File Provider Extension.
Да, Apple снажно препоручује коришћење NSFileCoordinator за све операције са Ubiquity контејнер датотекама. Без координатора могућа су оштећења података при синхронизацији између уређаја и конфликти са File Provider Extension.
NSFilePresenter — протокол за примање обавештења о променама датотека. Омогућава апликацији да реагује на промене направљене од стране других процеса: ажурира UI при модификацији, обрађује премештање или се припрема за брисање датотеке.
Пет типова: ReadingIntent (читање), WritingIntent (писање), ReadingIntent са .withoutChanges (читање без праћења), WritingIntent са .contentIndependentMetadataOnly (само метаподаци) и WritingIntent са .forDeleting (брисање). Сваки одређује ниво приступа датотеци.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође