البرمجة غير المتزامنة في Swift: دليل شامل للمبتدئين

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة في البرمجة غير المتزامنة في Swift

\n\n

نادرًا ما تخلو تطبيقات الهواتف المحمولة الحديثة من طلبات الشبكة، أو العمل مع قواعد البيانات، أو معالجة الملفات الكبيرة. كل هذه العمليات تستغرق وقتًا، وإذا تم تنفيذها في الخيط الرئيسي، فسيتجمد واجهة التطبيق وسيحصل المستخدم على تجربة غير سارة. وهنا يأتي دور البرمجة غير المتزامنة.

\n\n

قبل ظهور Swift 5.5، كان المطورون يستخدمون الإغلاقات (completion handlers) أو المكتبات الخارجية (Combine، RxSwift)، مما أدى غالبًا إلى "جحيم الاستدعاءات الراجعة" وكود يصعب قراءته. مع إطلاق النموذج الجديد Swift Concurrency (async/await)، أصبحت كتابة الكود غير المتزامن بنفس سهولة ووضوح الكود المتزامن.

\n\n

في هذا الدليل، سنشرح المفاهيم الأساسية للبرمجة غير المتزامنة في Swift من خلال أمثلة عملية. ستتعلم كيفية استخدام async/await و Task و Actor وأدوات أخرى لإنشاء تطبيقات سريعة وسريعة الاستجابة لنظامي iOS و macOS.

\n\n

المفاهيم الأساسية لـ Swift Concurrency

\n\n

1. Async و Await: أساس عدم التزامن

\n\n

الكلمتان المفتاحيتان async و await هما قلب النموذج الجديد. async تعلن عن دالة على أنها غير متزامنة، بينما await توقف التنفيذ مؤقتًا لحين الحصول على النتيجة، دون حظر الخيط.

\n\n

لننظر إلى مثال بسيط: تحميل البيانات من الشبكة.

\n\n
import Foundation\n\n// تعريف دالة غير متزامنة\nfunc fetchUserData() async throws -> String {\n    let url = URL(string: "https://api.example.com/user/1")!\n    let (data, _) = try await URLSession.shared.data(from: url)\n    return String(data: data, encoding: .utf8) ?? "خطأ"\n}\n\n// استدعاء الدالة غير المتزامنة\nTask {\n    do {\n        let userData = try await fetchUserData()\n        print("بيانات المستخدم: \\(userData)")\n    } catch {\n        print("خطأ في التحميل: \\(error.localizedDescription)")\n    }\n}
\n\n

لاحظ: try await يعني أننا ننتظر نتيجة قد ترمي خطأ. يبدو الكود وكأنه كود متزامن عادي، لكنه لا يحظر الخيط الرئيسي.

\n\n

2. Task: نقطة الدخول إلى العالم غير المتزامن

\n\n

لا يمكن استدعاء الدوال غير المتزامنة إلا من سياق غير متزامن آخر. لتشغيل عملية غير متزامنة من كود متزامن (مثل من viewDidLoad())، يتم استخدام Task.

\n\n
class ViewController: UIViewController {\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \n        // تشغيل مهمة غير متزامنة\n        Task {\n            let data = await loadData()\n            updateUI(with: data)\n        }\n    }\n    \n    func loadData() async -> String {\n        // محاكاة تحميل طويل\n        try? await Task.sleep(nanoseconds: 2_000_000_000)\n        return "البيانات المحملة"\n    }\n    \n    func updateUI(with data: String) {\n        print("تحديث واجهة المستخدم: \\(data)")\n    }\n}
\n\n

مهم: Task ينشئ مهمة غير متزامنة جديدة يتم تنفيذها في خيط خلفية. لتحديث واجهة المستخدم، يجب العودة إلى الخيط الرئيسي - بشكل افتراضي، يقوم await بذلك تلقائيًا.

\n\n

3. Actor: الحماية من سباق البيانات

\n\n

عند العمل مع تعدد الخيوط، غالبًا ما تظهر مشكلة سباق البيانات (data race)، حيث تقوم عدة خيوط بتعديل متغير واحد في نفس الوقت. تقدم Swift حلاً أنيقًا - Actor.

\n\n

Actor هو نوع مرجعي يضمن أن خيطًا واحدًا فقط يمكنه الوصول إلى حالته القابلة للتعديل في أي لحظة.

\n\n
actor Counter {\n    private var value = 0\n    \n    func increment() {\n        value += 1\n    }\n    \n    func getValue() -> Int {\n        return value\n    }\n}\n\n// الاستخدام\nlet counter = Counter                

المدونات

توصيات الكتب