NSFileCoordinator یک کلاس Foundation در iOS و macOS است که دسترسی امن به فایلها را هنگام کار همزمان چندین رشته، فرآیند یا افزونه فراهم میکند. به گفته Apple Developer Documentation, 2024، NSFileCoordinator از شرایط رقابتی (race conditions) هنگام خواندن و نوشتن فایلها جلوگیری میکند و تضمین میکند که هیچ فرآیندی دادهها را در لحظه تغییر آنها توسط دیگری نمیخواند. هماهنگکننده در iCloud Drive، File Provider Extension و هرگونه عملیات فایل چندرشتهای استفاده میشود.
نکات اصلی
NSFileCoordinator — مکانیزم همگامسازی دسترسی به فایلها در سطح سیستمعامل است که توسط اپل در iOS 5 و macOS 10.7 Lion معرفی شد. برخلاف قفلهای سنتی (NSLock، pthread_mutex)، هماهنگکننده در سطح سیستم فایل کار میکند و میتواند دسترسی بین فرآیندهای مختلف را هماهنگ کند، نه فقط بین رشتههای یک برنامه.
نیاز به NSFileCoordinator از معماری Sandbox در iOS ناشی میشود: هر فرآیند (برنامه، افزونه، سرویس سیستمی) در یک محیط ایزوله با دسترسی خاص خود به فایلها کار میکند. هنگامی که چندین فرآیند سعی میکنند همزمان یک فایل را بخوانند و بنویسند (مثلاً هنگام همگامسازی iCloud Drive)، بدون هماهنگکننده شرایط رقابتی ایجاد میشود: فرآیند A فایل را در لحظهای میخواند که فرآیند B قبلاً بخشی از آن را بازنویسی کرده است.
به گفته WWDC 2023، اپل اکیداً توصیه میکند از NSFileCoordinator برای همه عملیاتهای فایل در Ubiquity container (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 container (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.
بله، اپل اکیداً توصیه میکند از NSFileCoordinator برای همه عملیاتهای فایل Ubiquity container استفاده کنید. بدون هماهنگکننده، آسیب داده هنگام همگامسازی بین دستگاهها و تعارضات با File Provider Extension ممکن است رخ دهد.
NSFilePresenter — پروتکلی برای دریافت اعلانهای تغییرات فایل. به برنامه اجازه میدهد به تغییرات انجام شده توسط فرآیندهای دیگر واکنش نشان دهد: بهروزرسانی UI هنگام تغییر، مدیریت جابجایی یا آمادهسازی برای حذف فایل.
پنج نوع: ReadingIntent (خواندن)، WritingIntent (نوشتن)، ReadingIntent با .withoutChanges (خواندن بدون ردیابی)، WritingIntent با .contentIndependentMetadataOnly (فقط فراداده) و WritingIntent با .forDeleting (حذف). هرکدام سطح دسترسی به فایل را تعیین میکند.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید