Az NSFileCoordinator egy Foundation osztály iOS-ben és macOS-ben, amely biztonságos hozzáférést biztosít a fájlokhoz, amikor több szál, folyamat vagy bővítmény egyidejűleg dolgozik. A Apple Developer Documentation, 2024 szerint az NSFileCoordinator megakadályozza a versenyhelyzeteket (race conditions) a fájlok olvasása és írása során, garantálva, hogy egyetlen folyamat sem olvassa az adatokat abban a pillanatban, amikor azokat egy másik módosítja. A koordinátort az iCloud Drive-ban, a File Provider Extension-ben és bármely több szálú fájlműveletben használják.
Főbb pontok
NSFileCoordinator — egy operációs rendszer szintű fájlhozzáférés-szinkronizációs mechanizmus, amelyet az Apple az iOS 5 és macOS 10.7 Lion rendszerben vezetett be. A hagyományos zárolásokkal (NSLock, pthread_mutex) ellentétben a koordinátor a fájlrendszer szintjén működik, és képes koordinálni a hozzáférést különböző folyamatok között, nem csak egy alkalmazás szálai között.
Az NSFileCoordinator szükségessége az iOS Sandbox architektúrájából ered: minden folyamat (alkalmazás, bővítmény, rendszerszolgáltatás) izolált környezetben működik, saját fájlhozzáféréssel. Amikor több folyamat próbálja egyidejűleg olvasni és írni ugyanazt a fájlt (például iCloud Drive szinkronizálásnál), koordinátor nélkül versenyhelyzetek alakulnak ki: az A folyamat abban a pillanatban olvassa a fájlt, amikor a B folyamat már részben felülírta azt.
A WWDC 2023 szerint az Apple erősen ajánlja az NSFileCoordinator használatát minden Ubiquity container (iCloud Drive) fájlművelethez és a File Provider Extension-nel való munkához. A koordináció figyelmen kívül hagyása az adatsérülés és a nem reprodukálható hibák egyik gyakori oka az iOS alkalmazásokban.
Koordinációs szándék (NSFileCoordinator.ReadingIntent / WritingIntent) — egy objektum, amely deklarálja a szál vagy folyamat által végrehajtani kívánt művelet típusát. A koordinátor ezeket a szándékokat használja a hozzáférési sorrend meghatározásához és a konfliktusok feloldásához.
| Szándék típusa | Leírás | Mikor használjuk |
|---|---|---|
| ReadingIntent | Fájl olvasása módosítás nélkül | Dokumentum megnyitása, adatok betöltése |
| WritingIntent | Írás a tartalom lehetséges módosításával | Dokumentum mentése, szerkesztés |
| ReadingIntent(URL, options: .withoutChanges) | Olvasás változások követése nélkül | Tartalom gyors előnézete |
| WritingIntent(URL, options: .contentIndependentMetadataOnly) | Csak metaadatok módosítása | Dátum vagy attribútumok frissítése |
| WritingIntent(URL, options: .forDeleting) | Fájl törlése | Dokumentum törlése a felhasználó által |
Koordinációs szabályok: több egyidejű olvasás megengedett (ha nincs aktív írás), az írás exkluzív — sem olvasás, sem írás nem engedélyezett az írási művelet során. Ez megfelel a readers-writer lock modellnek, de kiegészítő támogatással a folyamatok közötti koordinációhoz launchd és XPC segítségével.
Fontos árnyalat: Az NSFileCoordinator nem akadályozza meg a fájlhoz való hozzáférést a szokásos NSData vagy FileManager segítségével — csak azokat a műveleteket koordinálja, amelyek kifejezetten koordinációs blokkokba vannak csomagolva. Ha egy másik szál közvetlenül, a koordinátor megkerülésével fér hozzá a fájlhoz, pontosan azok a versenyhelyzetek alakulnak ki, amelyeket a koordinátornak meg kellene akadályoznia.
Alapminta az NSFileCoordinator használatához három lépésből áll: a koordinátor példányának létrehozása, a szándék deklarálása (olvasás vagy írás), és a művelet végrehajtása a koordinációs blokkon belül. A koordinátor garantálja, hogy egyetlen másik koordinátor sem dolgozik egyidejűleg ugyanazzal a fájllal.
import Foundation
let coordinator = NSFileCoordinator()
let fileURL = getDocumentURL()
// Biztonságos olvasás
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)
}
// Biztonságos írás
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)"
)
}
}
Kötegelt művelet — a koordinátor több fájlt is feldolgozhat egyetlen műveletben szándékok tömbjének segítségével. Ez kényelmes fájlok egyetlen tranzakcióként történő áthelyezéséhez, másolásához vagy törléséhez. Ha az egyik szándék nem hajtható végre, a teljes művelet hibával megszakad.
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)
}
Aszinkron koordináció — az iOS 15-től kezdve az NSFileCoordinator támogatja az aszinkron metódusokat completion handler-rel, lehetővé téve a koordináció végrehajtását a hívó szál blokkolása nélkül. Ez kritikus fontosságú a UI szál esetében, ahol a koordinációra való szinkron várakozás másodpercekre befagyaszthatja a felületet.
NSFilePresenter — egy protokoll, amelyet egy objektum az NSFileCoordinator által koordinált fájlok változásairól szóló értesítések fogadására implementál. Ha az alkalmazás egy olyan fájl tartalmát jeleníti meg, amelyet egy másik folyamat módosíthat (például az iCloud Drive új verziót szinkronizál), az NSFilePresenter implementációja lehetővé teszi a felület időben történő frissítését.
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)
}
}
Protokoll metódusai: a presentedItemDidChange a fájl tartalmának változásakor hívódik meg, a presentedItemDidMove(to:) — a fájl áthelyezése után, az accommodatePresentedItemDeletion — a fájl másik folyamat általi törlése előtt (lehetővé teszi az alkalmazás számára a fájl megfelelő bezárását). Ezenkívül a protokoll támogatja a verziókezelést a presentedItemDidGainVersion: és presentedItemDidLoseVersion: segítségével.
Fontos: Az NSFilePresenter-t regisztrálni kell a rendszerben az NSFileCoordinator.addFilePresenter: segítségével. Regisztráció nélkül az értesítések nem kerülnek kézbesítésre. A regisztráció egyszer történik az alkalmazás indításakor, és nem igényel újraregisztrációt a presenter újbóli létrehozásakor.
Mindig használja a koordinátort az Ubiquity container (iCloud Drive) és a bővítmények számára elérhető könyvtárak fájljaihoz. Még ha az alkalmazás jelenleg egy szálú is, a jövőbeli frissítések vagy rendszerváltozások párhuzamos hozzáférést adhatnak hozzá, és a koordináció hiánya nehezen megtalálható hibákhoz vezet.
Minimalizálja a koordinációs blokkban töltött időt. Amíg a blokk végrehajtódik, más folyamatok nem férhetnek hozzá a fájlhoz. A blokkon belüli hosszú műveletek (összetett adatfeldolgozás, hálózati kérések) blokkolják a teljes fájlhozzáférési rendszert. Csak az adatok olvasását vagy írását végezze a blokkon belül, a feldolgozást pedig azon kívül.
Kerülje a deadlock-okat: ne hívja a koordinátort egy másik koordinátor blokkján belül ugyanarra a fájlra — ez kölcsönös blokkoláshoz vezet. Használjon kötegelt műveleteket (szándékok tömbje) beágyazott hívások helyett. Ha a beágyazás szükséges, használjon különböző sorokat vagy különböző URL-eket.
A objc.io (2024) szerint az NSFileCoordinator-ral való munka tipikus hibái közé tartozik: a hibakezelés hiánya a completion handler-ben (befejezetlen műveletekhez vezet); koordináció csak írásra, de nem olvasásra; elavult szinkron API használata a UI szálban; az NSFilePresenter protokoll figyelmen kívül hagyása az iCloud Drive-val való munka során. Az utolsó hiba a legravaszabb: az alkalmazás elavult adatokat jelenít meg, nem tudva, hogy a fájl már megváltozott.
Gyakran ismételt kérdések
NSFileCoordinator — Foundation osztály a biztonságos fájlhozzáféréshez több szálból vagy folyamatból. Megakadályozza a race condition-ket az olvasási és írási műveletek koordinálásával a fájlrendszer szintjén.
NSLock csak egy folyamaton belül (szálak között) működik. Az NSFileCoordinator koordinálja a hozzáférést különböző folyamatok és bővítmények között, beleértve az iCloud Drive szinkronizálást és a File Provider Extension-t.
Igen, az Apple erősen ajánlja az NSFileCoordinator használatát minden Ubiquity container fájlművelethez. Koordinátor nélkül adatsérülés lehetséges az eszközök közötti szinkronizálás során és konfliktusok a File Provider Extension-nel.
NSFilePresenter — protokoll a fájlváltozásokról szóló értesítések fogadására. Lehetővé teszi az alkalmazás számára, hogy reagáljon a más folyamatok által végzett változásokra: UI frissítése módosításkor, áthelyezés kezelése vagy felkészülés a fájl törlésére.
Öt típus: ReadingIntent (olvasás), WritingIntent (írás), ReadingIntent .withoutChanges opcióval (olvasás követés nélkül), WritingIntent .contentIndependentMetadataOnly opcióval (csak metaadatok) és WritingIntent .forDeleting opcióval (törlés). Mindegyik meghatározza a fájlhoz való hozzáférés szintjét.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is