Actor — ما هو، عزل البيانات والتزامن

المؤلف: IT Sectr نُشر: 2026-06-18 وقت القراءة: 11 دق

Actor هو نوع تم تقديمه في Swift 5.5+ يحل مشكلة سباقات البيانات على مستوى اللغة. على عكس الأقفال اليدوية وطوابير DispatchQueue، يقوم actor بعزل حالته تلقائياً ومزامنة الوصول إليها. هذا يعني أن خيطين لا يمكنهما تعديل نفس الخاصية من نوع actor في وقت واحد، مما يلغي حالات السباق دون جهد إضافي من المطور. الآلية تعتمد على مفهوم عزل actor، حيث يتتبع المترجم الوصول إلى خصائص وطرق actor. وفقاً لشركة Apple، 2025، فإن نموذج actor هو جزء أساسي من نظام التزامن في Swift.

النقاط الرئيسية

  • Actor هو نوع يعزل حالته تلقائياً عن سباقات البيانات على مستوى المترجم
  • العزل يضمن أن خيطاً واحداً فقط يصل إلى مثيل actor في كل مرة
  • استدعاءات طرق actor تنفذ بشكل غير متزامن عبر آلية async/await
  • Nonisolated يسمح بتعطيل العزل بشكل انتقائي لأعضاء actor فرديين
  • Reentrancy يسمح بإعادة الدخول إلى actor، مما يمنع حالات الجمود

ما هو Actor في Swift؟

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

صيغة تعريف Actor

لتعريف actor، يتم استخدام الكلمة المفتاحية actor متبوعة بأقواس متعرجة مع أعضائه. من الناحية التركيبية، يشبه actor الكلاس، لكن سلوكه يختلف جذرياً.

swift
actor BankAccount {
    private var balance: Double
    
    init(initialBalance: Double) {
        self.balance = initialBalance
    }
    
    func deposit(amount: Double) {
        balance += amount
    }
    
    func getBalance() -> Double {
        return balance
    }
}

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

كيف يعمل عزل البيانات في Actor

عزل البيانات هو المفهوم الأساسي لـ actor. يضمن actor الوصول الحصري المتبادل إلى حالته من خلال آلية منفذ actor. لكل actor منفذ خاص به يعالج جميع الوصول إلى أعضائه المعزولة بشكل تسلسلي.

كيف يعمل العزل

عندما يستدعي كود خارج actor طريقته، يتم وضع الاستدعاء في طابور منفذ actor. ينفذ actor مهمة واحدة فقط في كل مرة، مما يضمن عدم وجود سباقات. إذا استدعى خيطان deposit في وقت واحد، ينتظر الاستدعاء الثاني اكتمال الأول.

swift
let account = BankAccount(initialBalance: 1000.0)
// استدعاء غير متزامن — مطلوب من خارج actor
await account.deposit(amount: 500.0)
let currentBalance = await account.getBalance()

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

الاختلافات الرئيسية بين Actor والكلاس

Actor والكلاس كلاهما نوعان مرجعيان، لكن سلوكهما في بيئة متعددة الخيوط يختلف جذرياً. لا يوفر الكلاس أي حماية تلقائية ضد السباقات، بينما يدمجها actor على مستوى المترجم من خلال نظام الأنواع.

الخاصيةActorكلاس
الحماية من السباقاتتلقائية، على مستوى المترجمتتطلب مزامنة يدوية
الوصول إلى الخصائصفقط عبر await من الخارجمباشر، بدون مزامنة
الوراثةفقط من actors أخرىوراثة كلاس قياسية
توافق البروتوكولاتيمكنه التوافق مع البروتوكولاتقياسي
الأداءعبء منخفض مع العزلأسرع بدون مزامنة

وراثة Actor

يمكن لـ actor أن يرث فقط من actor آخر ولا يمكنه الوراثة من كلاس. هذا مقصود لأن الكلاس يفتقر إلى آلية عزل actor، وخلط الأنواع من شأنه أن يكسر ضمانات الأمان.

swift
actor SavingsAccount: BankAccount {
    func applyInterest(rate: Double) {
        let interest = balance * rate
        balance += interest
    }
}

الاستدعاءات غير المتزامنة لطرق Actor

الاستدعاءات غير المتزامنة هي آلية التفاعل مع actor من كود خارجي. نظراً لأن actor يعزل حالته، فإن أي وصول إلى أعضائه من الخارج يتطلب await. يتيح ذلك لـ Swift ضمان أن الكود المستدعي لا يحجب الخيط ويمكن لـ actor معالجة الطلبات الأخرى.

الـ Actors العالمية والمحلية

بالإضافة إلى أنواع actor المعلنة، يدعم Swift الـ actors العالمية — السمة @MainActor، التي تميز الكلاسات أو الخصائص أو الطرق بأنها قابلة للتنفيذ على الخيط الرئيسي. هذا مفيد بشكل خاص لكود واجهة المستخدم في تطبيقات iOS.

swift
@MainActor
class ViewModel: ObservableObject {
    @Published var title: String = ""
    
    func updateTitle() {
        // هذا الكود مضمون للتنفيذ على الخيط الرئيسي
        title = "New Title"
    }
}

استخدام @MainActor يلغي الحاجة إلى استدعاء DispatchQueue.main.async يدوياً، مما يجعل الكود أنظف وأكثر أماناً. يتحقق المترجم من أن التبديل إلى الخيط الرئيسي يحدث بشكل صحيح.

سياقات Nonisolated و Actor-Isolated

Nonisolated هي كلمة مفتاحية تسمح بتحديد طريقة أو خاصية محسوبة لـ actor على أنها غير معزولة. هذه الأعضاء لا يمكنها الوصول إلى الحالة المعزولة لـ actor، لكن يمكن استدعاؤها بدون await من خارج actor.

الدوال Nonisolated

طرق nonisolated مفيدة للحسابات التي لا تعتمد على الحالة القابلة للتغيير لـ actor. على سبيل المثال، طريقة formatBalance لا تصل إلى balance مباشرة، بل تقوم فقط بتنسيق القيمة الممررة — مثل هذه الطريقة آمنة لجعلها nonisolated.

swift
actor BankAccount {
    private var balance: Double = 0
    
    nonisolated func formatBalance(amount: Double) -> String {
        return "$\(amount)"
    }
}

الأعضاء nonisolated يتم تنفيذهم بشكل متزامن ولا يتطلبون await. ومع ذلك، لا يمكنهم قراءة الخصائص المعزولة لـ actor مباشرة. إذا كانت طريقة nonisolated تحتاج إلى قيمة من actor، فيجب تمريرها كمعامل.

Reentrancy وإعادة الدخول

Reentrancy هي آلية تسمح بإعادة الدخول إلى actor أثناء انتظار استدعاء غير متزامن. بدون reentrancy، يمكن لـ actor أن يتوقف إلى الأبد إذا انتظرت إحدى طرقه طريقة أخرى تنتظر الأولى بدورها.

كيف تعمل إعادة الدخول

عندما ينفذ الكود داخل actor await، يعلق actor المهمة الحالية ويمكنه معالجة مهمة أخرى في الطابور. بعد اكتمال await، تستأنف المهمة. هذا يمنع حالات الجمود، لكنه يتطلب الحذر: حالة actor بين نقاط await قد تتغير.

swift
actor DataProcessor {
    var cache: [Int: String] = [:]
    
    func process(id: Int) async -> String {
        if let cached = cache[id] {
            return cached
        }
        // await — نقطة إعادة الدخول
        let result = await fetchData(id: id)
        // قد تكون الذاكرة المؤقتة تغيرت بعد await — أعد التحقق
        cache[id] = result
        return result
    }
}

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

الأسئلة الشائعة

كيف يختلف Actor عن الكلاس في Swift؟

Actor يعزل حالته تلقائياً عن سباقات البيانات، ويتطلب await للوصول الخارجي. الكلاس لا يوفر هذه الحماية — المطور مسؤول عن المزامنة عبر الأقفال أو الطوابير. actor يرث فقط من actor، والكلاس يرث من كلاس.

هل يمكن الوراثة من Actor؟

نعم، يمكن لـ actor أن يرث من actor آخر. الفئة الفرعية تحصل على جميع الخصائص والطرق المعزولة للوالد. لا يمكن لـ actor أن يرث من كلاس لأن الكلاسات تفتقر إلى آلية عزل actor على مستوى المترجم.

ما هو سياق actor-isolated؟

سياق actor-isolated هو منطقة كود يُسمح فيها بالوصول المباشر إلى الحالة القابلة للتغيير لـ actor. داخل طرق actor المميزة بأنها معزولة (افتراضياً)، يمكن قراءة وكتابة الخصائص بدون await. يتحقق المترجم من حدود العزل.

كيف يتم تمرير البيانات من Actor إلى كود خارجي؟

يتم تمرير البيانات من actor عبر طرق غير متزامنة تعيد أنواع Sendable، أو عبر طرق nonisolated التي تقبل القيم كمعاملات. يمكن أيضاً إنشاء خاصية غير متزامنة تعيد لقطة من حالة actor كهيكل Sendable.

هل يدعم Actor توافق البروتوكولات؟

نعم، يمكن لـ actor أن يتوافق مع البروتوكولات. إذا كان البروتوكول يحتوي على متطلبات معزولة (actor-isolated)، فإنها تصبح تلقائياً معزولة لـ actor. للطرق غير المتزامنة في البروتوكولات، يمكن تحديد أنه يجب استدعاؤها على actor محدد باستخدام علامة isolated.

الخلاصة

  • Actor هو نوع مرجعي مع عزل تلقائي للبيانات، تم تقديمه في Swift 5.5+
  • العزل يعمل من خلال منفذ actor يعالج الطلبات بشكل تسلسلي
  • الوصول الخارجي إلى actor يتطلب await — وهذا يضمن عدم وجود سباقات
  • Nonisolated يسمح بتعريف طرق متزامنة لا تصل إلى الحالة المعزولة
  • الـ Actors العالمية (@MainActor) توسع العزل إلى خيط التنفيذ بأكمله
  • Reentrancy يمنع حالات الجمود بالسماح بإعادة الدخول إلى actor أثناء await

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا