OperationQueue هي قائمة مهام عالية المستوى في iOS و macOS مبنية فوق Grand Central Dispatch. وفقًا لوثائق Apple Developer، 2026، يدير OperationQueue مثيلات Operation — كائنات تغلف وحدة عمل. على عكس DispatchQueue، يدعم OperationQueue التبعيات بين العمليات والأولويات ومراقبة KVO وإلغاء المهام قيد التشغيل. يدير OperationQueue تلقائيًا مجموعة من الخيوط، موزعًا العمليات على موارد النظام المتاحة.
النقاط الرئيسية
OperationQueue هي فئة من إطار Foundation تدير تنفيذ كائنات Operation. على عكس DispatchQueue، لا تتطلب OperationQueue تحديد الوضع التسلسلي أو المتزامن بشكل صريح — يتم التحكم في عدد العمليات التي يتم تنفيذها في وقت واحد بواسطة الخاصية maxConcurrentOperationCount. القيمة 1 تجعل القائمة تسلسلية، وأي قيمة أخرى تجعلها متزامنة.
Operation هي فئة مجردة تمثل وحدة عمل. كل عملية لها حالة: ready أو executing أو finished أو cancelled. الحالات متوافقة مع KVO (مراقبة القيمة الرئيسية)، مما يسمح بالتفاعل مع التغييرات — على سبيل المثال، تحديث الواجهة عند اكتمال العملية. تدير Operation تلقائيًا العلامات isExecuting و isFinished.
وفقًا لشركة Apple (2026)، تستخدم OperationQueue GCD داخليًا ولكنها تضيف وظائف غير متوفرة في DispatchQueue: التبعيات والأولويات والإلغاء للعمليات. إذا دخل التطبيق الخلفية، تعلق OperationQueue التنفيذ وتستأنفه عند العودة. تراعي OperationQueue أيضًا تلقائيًا عدد أنوية المعالج وتختار العدد الأمثل من الخيوط.
تمر كل عملية بأربع حالات: pending (قيد الانتظار)، ready (جاهزة)، executing (قيد التنفيذ)، وfinished (مكتملة). يمكن أن تحدث حالة cancelled في أي مرحلة قبل الاكتمال. يتم تتبع انتقالات الحالة عبر KVO — وهذا هو الأساس للتحديثات التفاعلية للواجهة. تزيل OperationQueue تلقائيًا العمليات المكتملة من القائمة وتخطر العمليات التابعة بأن المتطلب الأساسي قد تم استيفاؤه، مما يؤدي إلى تشغيل تنفيذها.
Operation هي فئة مجردة تتطلب تجاوز الطريقة main() أو start(). يتم وضع كود المهمة في الطريقة main()، ويتم إدارة حالتي isExecuting و isFinished تلقائيًا. للعمليات غير المتزامنة، يلزم تجاوز start() وإدارة علامات الحالة يدويًا.
BlockOperation هو تنفيذ ملموس لـ Operation ينفذ كتلة برمجية واحدة أو أكثر. يصبح BlockOperation متزامنًا إذا أضفت عدة كتل عبر addExecutionBlock(). تكتمل العملية فقط بعد تنفيذ جميع الكتل المضافة. BlockOperation هو بديل مناسب للمهام البسيطة دون وراثة.
| الخاصية | Operation | BlockOperation |
|---|---|---|
| نوع الفئة | مجردة | ملموسة |
| الوراثة | مطلوبة | غير مطلوبة |
| عدم التزامن | إدارة يدوية لـ KVO | تلقائية |
| كتل برمجية | واحدة في main() | واحدة أو عدة |
| الاستخدام | مهام معقدة مع حالة | مهام بسيطة لمرة واحدة |
| مناسب لـ | التبعيات، الإلغاء، التقدم | كتل سريعة، الإكمال |
| الذاكرة | أعلى بسبب KVO والحالة | أدنى، خفيفة الوزن |
لإنشاء عملية مخصصة، قم باشتقاق فئة من Operation وتجاوز main(). في الداخل، تحقق من العلامة isCancelled قبل العمليات المكلفة لضمان إلغاء سريع. هذا أمر بالغ الأهمية لتنزيل الملفات الكبيرة أو معالجة البيانات على دفعات. الاختيار بين Operation و BlockOperation يعتمد على تعقيد المهمة: للإجراءات البسيطة لمرة واحدة، يكفي BlockOperation؛ للمنطق القابل لإعادة الاستخدام مع الحالة، قم باشتقاق فئة من Operation.
التبعيات هي الميزة الرئيسية لـ OperationQueue مقارنة بـ DispatchQueue. تحدد الطريقة addDependency(_:) أن العملية B يتم تنفيذها فقط بعد اكتمال العملية A. تشكل التبعيات رسمًا بيانيًا موجهًا غير دائري (DAG): إذا تمت إضافة تبعية دائرية، تتجاهلها القائمة ولا تبدأ العمليات.
أولوية العملية يتم تعيينها عبر الخاصية queuePriority بالقيم: .veryLow، .low، .normal، .high، .veryHigh. تؤثر الأولوية على ترتيب البدء بين العمليات الجاهزة ولكنها لا تلغي التبعيات. OperationQueue تحل التبعيات أولاً، ثم تطبق الأولوية بين العمليات المتاحة.
سيناريو نموذجي — تحميل بيانات الملف الشخصي: أولاً تحميل المستخدم، ثم بناءً على معرفه تحميل الأصدقاء والمنشورات. تعيين تبعية بين تحميل المستخدم وتحميل الأصدقاء يضمن الترتيب الصحيح دون معالجات إكمال متداخلة.
الخاصية maxConcurrentOperationCount تحد من عدد العمليات التي يتم تنفيذها في وقت واحد. القيمة 1 تنشئ قائمة تسلسلية، القيمة الافتراضية (NSOperationQueueDefaultMaxConcurrentOperationCount) هي الأمثل للنظام وتعتمد على الحمل الحالي للجهاز. التكوين المناسب لهذه المعلمة يمنع الاستهلاك المفرط للموارد: لتحميل الصور، 4–6 عمليات متزامنة كافية؛ للمهام المكثفة لوحدة المعالجة المركزية، استخدم عدد أنوية المعالج.
الاختيار بين OperationQueue و DispatchQueue يعتمد على تعقيد المهمة. DispatchQueue هي أداة خفيفة للاستدعاءات غير المتزامنة البسيطة. OperationQueue هي حل أثقل للسيناريوهات المعقدة مع العديد من المهام المترابطة. توصي Apple بالبدء بـ DispatchQueue والانتقال إلى OperationQueue فقط عند الحاجة إلى التبعيات أو الإلغاء. لمعظم مشاريع iOS، مزيج من كلا الأداتين يعطي توازنًا أمثل بين الأداء والمرونة.
وفقًا لـ Ray Wenderlich (2025)، في مشاريع iOS الكبيرة، يتم استخدام OperationQueue لتحميل المحتوى مع التقدم والإلغاء، بينما يتم استخدام DispatchQueue لجميع العمليات غير المتزامنة الأخرى. النسبة حوالي 20 إلى 80 لصالح DispatchQueue.
دعنا نلقي نظرة على ثلاثة أمثلة: BlockOperation بسيط، Operation مخصصة مع تبعيات، وعملية قابلة للإلغاء لتحميل البيانات.
أبسط حالة — تنفيذ كتلة على OperationQueue ومعالجة النتيجة عبر completionBlock. كل Operation لها خاصية completionBlock مدمجة، يتم استدعاؤها بعد انتهاء main().
let queue = OperationQueue()
let operation = BlockOperation()
operation.addExecutionBlock {
let data = NetworkService.fetchData()
OperationQueue.main.addOperation {
self.updateUI(data)
}
}
queue.addOperation(operation)
التبعية تضمن أن parseOperation تبدأ فقط بعد اكتمال downloadOperation. هذا يلغي الحاجة إلى عمليات استدعاء متداخلة.
let download = BlockOperation { self.downloadJSON() }
let parse = BlockOperation { self.parseJSON() }
parse.addDependency(download)
let queue = OperationQueue()
queue.addOperations([download, parse], waitUntilFinished: false)
قم بتجاوز main() مع فحوصات دورية لـ isCancelled. هذا يسمح للعملية بالتوقف فورًا عند الإلغاء، دون انتظار اكتمال عملية مكلفة.
class ImageLoadOperation: Operation {
override func main() {
guard !self.isCancelled else { return }
let image = self.downloadImage()
guard !self.isCancelled else { return }
OperationQueue.main.addOperation { self.display(image) }
}
}
إلغاء العملية يعيّن العلامة isCancelled إلى true، لكنه لا يوقف الطريقة main() قيد التشغيل. يجب أن يتحقق الكود داخل main() من isCancalled بنفسه وينهي عند الضرورة. هذا قرار معماري من Apple — يسمح للمطور بتحرير الموارد بشكل صحيح عند الإلغاء.
مراقبة KVO للخاصيتين isFinished و isExecuting تسمح بالتفاعل مع اكتمال العمليات دون استدعاءات صريحة. تزيل OperationQueue تلقائيًا العمليات المكتملة من القائمة، لكنها تبقى في الذاكرة طالما هناك مراجع قوية لها. KVO هي الأساس لدمج OperationQueue مع الأطر التفاعلية مثل RxSwift أو Combine.
الاشتراك في isCancelled عبر KVO يسمح بتحديث الواجهة عند إلغاء العملية — على سبيل المثال، إظهار عنصر نائب بدلاً من تحميل تم إلغاؤه. الخاصية isCancelled متوافقة مع KVO، مما يجعلها ملائمة للخطوط التفاعلية.
لا تنشئ أعدادًا كبيرة من العمليات — كل Operation هي كائن منفصل في الذاكرة. إذا كانت المهمة قصيرة ولا تتطلب تبعيات، استخدم DispatchQueue مباشرة. OperationQueue مبررة للسيناريوهات المعقدة مع تبعيات صريحة وإلغاء ومراقبة التقدم.
تحقق من isCancelled قبل العمليات المكلفة داخل الطريقة main(). في حالات تنزيل الملفات أو معالجة الصور، التحقق بعد كل خطوة مهمة يضمن استجابة سريعة للإلغاء. استخدم if isCancelled { return } في بداية main() وبعد كل عملية رئيسية.
أدر completionBlock بشكل صحيح. يتم استدعاء خاصية completionBlock للعملية بعد انتهاء main()، حتى إذا تم إلغاء العملية. تحقق من isCancelled داخل completionBlock لتجنب تحديث الواجهة ببيانات خاطئة. OperationQueue.main هي قائمة آمنة للخيوط لعمليات الواجهة، مشابهة لـ DispatchQueue.main.
تجنب التبعيات الدائرية — تؤدي إلى عدم بدء أي من العمليات في الدورة أبدًا. لا تكتشف OperationQueue الدورات تلقائيًا: إذا كانت A تعتمد على B و B تعتمد على A، فستظل كلتاهما في حالة ready إلى الأبد. خطط للرسم البياني للتبعيات مسبقًا.
الأسئلة الشائعة
OperationQueue مبنية فوق GCD وتضيف التبعيات والأولويات و KVO وإلغاء العمليات. DispatchQueue هي أداة أخف للمهام غير المتزامنة البسيطة دون هذه الإمكانيات.
اضبط الخاصية maxConcurrentOperationCount على 1. هذا يحول OperationQueue إلى قائمة تسلسلية مع الاحتفاظ بجميع المزايا — التبعيات والأولويات والإلغاء.
الطريقة cancel() تعيّن العلامة isCancelled لكنها لا توقف الطريقة main() قيد التنفيذ. يجب أن يتحقق كود العملية من isCancelled بنفسه وينهي. الإلغاء يعمل فقط للعمليات المعلقة والجاهزة.
يجب اشتقاق فئة من Operation عندما تحتاج إدارة حالة أو عدم تزامن أو إعادة استخدام المنطق. BlockOperation مناسب للمهام البسيطة لمرة واحدة دون وراثة.
لا، ما لم تستدع waitUntilFinished مع المعامل true على الخيط الرئيسي. يتم تنفيذ العمليات على خيوط خلفية افتراضيًا، ويتم إرجاع النتائج عبر OperationQueue.main.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.