مقدمة: لماذا نحتاج إلى قوائم انتظار المهام في Swift؟
في التطوير الحديث لنظامي iOS وmacOS، يعتمد أداء التطبيق بشكل مباشر على مدى فعالية إدارتك للخيوط. العمليات الطويلة - تحميل البيانات من الشبكة، معالجة الصور، العمل مع قاعدة البيانات - يجب ألا تمنع الخيط الرئيسي (Main Thread) المسؤول عن الواجهة. إذا كان الخيط الرئيسي مشغولاً، يرى المستخدم شاشة "مجمدة"، وقد يقوم النظام بإنهاء التطبيق قسراً.
قوائم انتظار المهام (Task Queues) تحل هذه المشكلة. فهي تسمح بتنفيذ الكود بشكل غير متزامن، متوازٍ أو تسلسلي، دون حظر واجهة المستخدم. في Swift، هناك ثلاث أدوات رئيسية لذلك: Grand Central Dispatch (GCD)، OperationQueue والنموذج الحديث async/await (Swift Concurrency). في هذه المقالة، سنشرحها بأمثلة عملية ونحدد متى نستخدم كل منها.
1. Grand Central Dispatch (GCD): النهج الكلاسيكي
GCD هي مكتبة منخفضة المستوى بلغة C تدير مجموعة من الخيوط. في Swift، يمكن العمل معها بسهولة من خلال قوائم الانتظار العامة (DispatchQueue).
1.1. الأنواع الأساسية لقوائم الانتظار في GCD
- Main Queue - قائمة انتظار تسلسلية للخيط الرئيسي. تُستخدم لتحديث واجهة المستخدم.
- Global Queues - قوائم انتظار متوازية بأولويات مختلفة (QoS:
.userInteractive،.userInitiated،.utility،.background). - Custom Queues - قوائم انتظار تقوم بإنشائها (يمكن أن تكون تسلسلية أو متوازية).
1.2. مثال: تحميل البيانات في الخلفية وتحديث واجهة المستخدم
لنفترض أننا بحاجة لتحميل JSON من خادم بعيد وعرض النتيجة في جدول.
DispatchQueue.global(qos: .userInitiated).async { // 1. عمل الخلفية: تحميل البيانات guard let url = URL(string: "https://api.example.com/data") else { return } let data = try? Data(contentsOf: url) // 2. العودة إلى الخيط الرئيسي لتحديث واجهة المستخدم DispatchQueue.main.async { // تحديث نموذج البيانات أو الجدول self.tableView.reloadData() }}1.3. استخدام DispatchGroup للمزامنة
عند الحاجة لتنفيذ عدة مهام متوازية وانتظار اكتمالها، استخدم DispatchGroup.
let group = DispatchGroup()var images: [UIImage] = []
for url in imageURLs { group.enter() DispatchQueue.global().async { if let data = try? Data(contentsOf: url), let image = UIImage(data: data) { images.append(image) } group.leave() }}
group.notify(queue: .main) { print("تم تحميل جميع الصور: \\(images.count)") // تحديث واجهة المستخدم}2. OperationQueue: مستوى أعلى من التجريد
OperationQueue مبنية فوق GCD، ولكنها توفر إمكانيات إضافية: إلغاء المهام، التبعيات بين العمليات، التحكم في الحد الأقصى لعدد العمليات المتوازية.
2.1. إنشاء وتشغيل العمليات
يمكن إنشاء العمليات عبر BlockOperation أو عن طريق الوراثة من Operation.
let queue = OperationQueue()queue.maxConcurrentOperationCount = 2 // تقييد إلى مهمتين متوازيتين
let operation1 = BlockOperation { print("بدأت العملية 1") sleep(2) print("اكتملت العملية 1")}
let operation2 = BlockOperation { print("بدأت العملية 2") sleep(1) print("اكتملت العملية 2")}
// تعيين تبعية: العملية 2 ستبدأ فقط بعد العملية 1operation2.addDependency(operation1)
queue.addOperations([operation1, operation2], waitUntilFinished: false)2.2. إلغاء العمليات
على عكس GCD، يمكن إلغاء العمليات. هذا أمر بالغ الأهمية إذا غادر المستخدم الشاشة، أو