كيف تتوقف عن الخوف من التأخيرات وتحب GCD في Swift 3 و4 و5
\n\nهل سبق لك أن كتبت كودًا كان من المفترض أن يتم تنفيذه بعد ثلاث ثوانٍ، لكنه عمل فورًا؟ أو العكس، انتظرت وقتًا طويلاً بينما كنت تخطط لبضع ميلي ثانية؟ مألوف؟ إذن أنت بالتأكيد واجهت dispatch_after — واحدة من أكثر أدوات Grand Central Dispatch (GCD) شيوعًا، ولكنها في نفس الوقت من أكثرها مكرًا.
\n\nفي السابق، في عصر Swift 2 وObjective-C، كانت هذه الطريقة تبدو وكأنها تعويذة: dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(nanoseconds)), dispatch_get_main_queue()). ولكن مع قدوم Swift 3 و4 و5، تمت إعادة كتابة API GCD بالكامل. الآن لم يعد مجرد تغيير اسم — بل أصبح طريقة جديدة في التفكير. في هذه المقالة، سنشرح كيفية كتابة dispatch_after في Swift على جميع الإصدارات الحالية، ونبدد الخرافات، ونقدم حلولاً جاهزة. هيا بنا!
ماذا حدث لـ dispatch_after؟ تاريخ موجز من الألم
\nقبل Swift 3، كان المطورون يستخدمون GCD بنمط C:
\nlet delay = dispatch_time(DISPATCH_TIME_NOW, Int64(2.0 * Double(NSEC_PER_SEC)))\ndispatch_after(delay, dispatch_get_main_queue()) {\n print("مرحبًا من الماضي!")\n}\nكان هذا يعمل، لكنه كان يبدو ضخمًا. في Swift 3، قررت Apple "تسويفتة" GCD، وتحويله إلى API كائني التوجه. الآن تحول dispatch_after إلى طريقة asyncAfter في الهيكل DispatchQueue. وهذا ليس مجرد تجميل — بل هو بناء جملة جديد تمامًا يتطلب الفهم.
الوصفة الأساسية: asyncAfter في Swift 3 و4 و5
\nبغض النظر عن إصدار Swift (3 أو 4 أو 5)، فإن بناء الجملة الأساسي لـ dispatch_after يبدو الآن متطابقًا. إليك أبسط مثال للتنفيذ المؤجل على الخيط الرئيسي:
\n\nlet delayInSeconds: Double = 2.0\nDispatchQueue.main.asyncAfter(deadline: .now() + delayInSeconds) {\n print("مرت ثانيتان!")\n}\nالنقاط الرئيسية:
\n- \n
- DispatchQueue.main — الخيط الرئيسي (واجهة المستخدم). \n
- .now() + delayInSeconds — إنشاء موعد نهائي (deadline) بالنسبة للحظة الحالية. \n
- asyncAfter — تنفيذ غير متزامن بعد الوقت المحدد. \n
هذا الكود يعمل في Swift 3.0 و4.0 و5.0 دون تغييرات. السحر هو أن Apple أبقت هذا API مستقرًا منذ عام 2016.
\n\nوماذا عن dispatch_time؟ العمل مع النانو ثانية
\nأحيانًا تحتاج إلى تحديد تأخير بالنانو ثانية (على سبيل المثال، للمؤقتات الدقيقة أو منطق الألعاب). في API الجديد يُستخدم DispatchTime:
\nlet nanoseconds: Int = 1_500_000_000 // 1.5 ثانية\nlet deadline = DispatchTime.now() + .nanoseconds(nanoseconds)\nDispatchQueue.global().asyncAfter(deadline: deadline) {\n print("تم التنفيذ بعد 1.5 ثانية في الخيط الخلفي")\n}\nيمكنك أيضًا استخدام الثوابت الجاهزة: .seconds(5)، .milliseconds(500) وحتى .microseconds(1000). هذا أسهل من الضرب في NSEC_PER_SEC.
أسئلة شائعة (وإجاباتها!) حول dispatch_after في Swift
\nفي Stack Overflow، جمع هذا السؤال آلاف المشاهدات. إليك أكثر الأخطاء شيوعًا التي يقع فيها المبتدئون.
\n\n1. لماذا يتم تنفيذ الكود الخاص بي فورًا وليس مع تأخير؟
\nالخطأ الأكثر شيوعًا هو الخلط بين asyncAfter و async. إذا نسيت تحديد deadline: أو كتبت DispatchQueue.main.async { ... }، سيتم تنفيذ الكود فورًا. السبب الثاني: تمرير قيمة سالبة. .now() + (-5.0) هو وقت مضى، وسيقوم GCD بتنفيذ الكتلة فورًا.
2. كيف ألغي dispatch_after؟
\nعلى عكس Timer، لا تحتوي asyncAfter على طريقة مدمجة cancel(). لكن هناك حلان:
- \n
- علامة الإلغاء: استخدم
Dispatc