NSFileCoordinator هو فئة Foundation في iOS وmacOS تضمن الوصول الآمن إلى الملفات عند عمل عدة خيوط أو عمليات أو إضافات في وقت واحد. وفقاً لوثائق مطوري Apple، 2024، يمنع NSFileCoordinator حالات السباق عند قراءة وكتابة الملفات، مما يضمن عدم قراءة أي عملية للبيانات بينما تقوم أخرى بتعديلها. يُستخدم المنسق في iCloud Drive وFile Provider Extension وأي عمليات ملفات متعددة الخيوط.
النقاط الرئيسية
NSFileCoordinator هو آلية مزامنة للوصول إلى الملفات على مستوى نظام التشغيل، قدمتها Apple في iOS 5 وmacOS 10.7 Lion. على عكس الأقفال التقليدية (NSLock، pthread_mutex)، يعمل المنسق على مستوى نظام الملفات ويمكنه تنسيق الوصول بين عمليات مختلفة، وليس فقط بين خيوط نفس التطبيق.
تنشأ الحاجة إلى NSFileCoordinator من بنية Sandbox في iOS: كل عملية (تطبيق، إضافة، خدمة نظام) تعمل في بيئة معزولة مع وصول خاص بها إلى الملفات. عندما تحاول عمليات متعددة قراءة وكتابة نفس الملف في وقت واحد (مثلاً، أثناء مزامنة iCloud Drive)، بدون منسق تحدث حالات سباق: العملية A تقرأ الملف بينما العملية B قد كتبت عليه جزئياً بالفعل.
وفقاً 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) | حذف ملف | حذف مستند من قبل المستخدم |
قواعد التنسيق: يُسمح بقراءات متعددة متزامنة (إذا لم يكن هناك كتابة نشطة)، الكتابة حصرية — لا يُسمح بأي قراءات أو كتابات أثناء عملية الكتابة. هذا يتبع نموذج قفل القراء-الكتّاب، ولكن مع دعم إضافي للتنسيق بين العمليات عبر launchd وXPC.
فارق دقيق مهم: NSFileCoordinator لا يمنع الوصول إلى الملفات عبر NSData أو FileManager العادية — فهو ينسق فقط العمليات المغلقة صراحةً في كتل التنسيق. إذا وصل خيط آخر إلى الملف مباشرة بدون المنسق، تحدث نفس حالات السباق التي صمم المنسق لمنعها.
النمط الأساسي لاستخدام NSFileCoordinator يتكون من ثلاث خطوات: إنشاء مثيل للمنسق، إعلان نية (قراءة أو كتابة)، وتنفيذ العملية داخل كتلة تنسيق. يضمن المنسق ألا يعمل أي منسق آخر مع نفس الملف في وقت واحد.
import Foundation
let coordinator = NSFileCoordinator()
let fileURL = getDocumentURL()
// Safe reading
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)
}
// Safe writing
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 طرقاً غير متزامنة مع معالج إكمال، مما يسمح بالتنسيق بدون حظر الخيط المستدعي. هذا أمر بالغ الأهمية لخيط 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) والأدلة التي يمكن الوصول إليها بواسطة الإضافات. حتى إذا كان التطبيق حالياً أحادي الخيط، فإن التحديثات المستقبلية أو تغييرات النظام قد تضيف وصولاً متوازياً، وسيؤدي نقص التنسيق إلى أخطاء يصعب العثور عليها.
قلل الوقت داخل كتلة التنسيق. أثناء تنفيذ الكتلة، لا يمكن للعمليات الأخرى الوصول إلى الملف. العمليات الطويلة داخل الكتلة (معالجة بيانات معقدة، طلبات شبكة) تمنع نظام الوصول إلى الملفات بأكمله. قم فقط بقراءة أو كتابة البيانات داخل الكتلة، وقم بالمعالجة خارجها.
تجنب حالات الجمود: لا تستدعي المنسق من داخل كتلة منسق آخر لنفس الملف — سيؤدي ذلك إلى جمود متبادل. استخدم العمليات الدفعية (مصفوفة من النوايا) بدلاً من الاستدعاءات المتداخلة. إذا كان التداخل ضرورياً، استخدم قوائم انتظار مختلفة أو عناوين URL مختلفة.
وفقاً objc.io (2024)، تشمل الأخطاء النموذجية عند العمل مع NSFileCoordinator: عدم معالجة الأخطاء في معالج الإكمال (يؤدي إلى عمليات غير مكتملة)؛ التنسيق للكتابة فقط وليس للقراءة؛ استخدام API المتزامن القديم في خيط UI؛ تجاهل بروتوكول NSFilePresenter عند العمل مع iCloud Drive. الخطأ الأخير هو الأكثر غدراً: يعرض التطبيق بيانات قديمة دون أن يدرك أن الملف قد تم تعديله بالفعل.
الأسئلة الشائعة
NSFileCoordinator هو فئة Foundation للوصول الآمن إلى الملفات من خيوط أو عمليات متعددة. يمنع حالات السباق من خلال تنسيق عمليات القراءة والكتابة على مستوى نظام الملفات.
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. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا