Event Bus ونمط Observer في Swift: التنفيذ والأمثلة

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

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

ابدأ الدورة

Event Bus ونمط Observer في Swift (iOS/macOS)

\n\n

في التطوير لأنظمة iOS و macOS، غالباً ما تنشأ الحاجة لتنظيم تفاعل ضعيف الاقتران بين مكونات التطبيق. نمط Observer وتنفيذه في شكل Event Bus (ناقل الأحداث) هو أداة قوية لحل هذه المشكلة. في هذه المقالة، سنشرح بالتفصيل كيفية تنفيذ Event Bus بلغة Swift، باستخدام الإمكانيات الحديثة للغة (Generics, closures, weak references).

\n\n

ما هو نمط Observer؟

\n\n

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

\n\n

في Swift، التطبيقات الأصلية لـ Observer هي:

\n
    \n
  • NotificationCenter — ناقل إشعارات عالمي، مدمج في Foundation.
  • \n
  • Key-Value Observing (KVO) — آلية مراقبة خصائص الكائنات.
  • \n
  • Combine framework (iOS 13+) — إطار عمل تفاعلي يدعم الناشرين والمشتركين.
  • \n
\n\n

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

\n\n

Event Bus: تنفيذ بسيط ومرن

\n\n

Event Bus هو مدير أحداث مركزي يسمح بالاشتراك في الأحداث وإرسالها دون معرفة مباشرة بالمشتركين. سنقوم بتنفيذه باستخدام الأدوية (Generics) والمراجع الضعيفة لتجنب تسرب الذاكرة.

\n\n

التنفيذ الأساسي لـ Event Bus

\n\n
import Foundation\n\n// بروتوكول لجميع الأحداث\nprotocol Event { }\n\n// أنواع أحداث محددة\nstruct UserLoggedInEvent: Event {\n    let userId: String\n    let userName: String\n}\n\nstruct DataLoadedEvent: Event {\n    let data: [String]\n}\n\n// كلاس Event Bus\nfinal class EventBus {\n    static let shared = EventBus()\n    private init() {}\n    \n    // قاموس لتخزين المشتركين\n    private var subscribers = [ObjectIdentifier: [Any]]()\n    \n    // الاشتراك في حدث\n    func subscribe<T: Event>(observer: AnyObject, handler: @escaping (T) -> Void) {\n        let key = ObjectIdentifier(T.self)\n        let wrapped = Subscription(observer: observer, handler: handler as Any)\n        \n        if subscribers[key] != nil {\n            subscribers[key]?.append(wrapped)\n        } else {\n            subscribers[key] = [wrapped]\n        }\n    }\n    \n    // إلغاء الاشتراك من جميع الأحداث لمراقب معين\n    func unsubscribe(observer: AnyObject) {\n        for key in subscribers.keys {\n            subscribers[key]?.removeAll(where: { subscription in\n                if let sub = subscription as? Subscription {\n                    return sub.observer === observer\n                }\n                return false\n            })\n        }\n    }\n    \n    // نشر حدث\n    func publish<T: Event>(event: T) {\n        let key = ObjectIdentifier(T.self)\n        guard let subs = subscribers[key] else { return }\n        \n        for subscription in subs {\n            if let sub = subscription as? Subscription {\n                if let handler = sub.handler as? (T) -> Void {\n                    handler(event)\n                }\n            }\n        }\n    }\n}\n\n// هيكل مساعد لتخزين الاشتراكات\nprivate struct Subscription {\n    weak var observer: AnyObject?\n    let handler: Any\n    \n    init(observer: AnyObject, handler: Any) {\n        self.observer = observer\n        self.handler = handler\n    }\n}\n
\n\n

استخدام Event Bus

\n\n
// ViewController يشترك في الأحداث\nclass LoginViewController: UIViewController {\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \n        // الاشتراك في الحدث                    

توصيات