Event Bus und das Observer-Pattern in Swift (iOS/macOS)
\n\nBei der Entwicklung für iOS und macOS besteht häufig die Notwendigkeit, eine lose gekoppelte Interaktion zwischen den Komponenten einer Anwendung zu organisieren. Das Observer-Pattern und seine Implementierung als Event Bus (Ereignisbus) sind ein leistungsstarkes Werkzeug, um diese Aufgabe zu lösen. In diesem Artikel werden wir im Detail besprechen, wie man einen Event Bus in Swift implementiert, unter Verwendung moderner Sprachfunktionen (Generics, Closures, Weak References).
\n\nWas ist das Observer-Pattern?
\n\nDas Observer-Pattern (Beobachter) definiert eine "Eins-zu-Viele"-Beziehung zwischen Objekten. Wenn ein Objekt (Herausgeber) seinen Zustand ändert, werden alle abhängigen Objekte (Abonnenten) automatisch benachrichtigt und aktualisiert. Dies vermeidet eine starke Kopplung und vereinfacht die Code-Wartung.
\n\nIn Swift sind native Implementierungen des Observer-Patterns:
\n- \n
NotificationCenter— ein globaler Benachrichtigungsbus, integriert in Foundation. \n - Key-Value Observing (KVO) — ein Mechanismus zur Beobachtung von Objekteigenschaften. \n
- Combine framework (iOS 13+) — ein reaktives Framework mit Unterstützung für Herausgeber und Abonnenten. \n
Allerdings ist oft eine leichtere und typsichere Implementierung erforderlich, insbesondere bei der Arbeit mit Legacy-Code oder in Projekten, in denen Combine nicht verfügbar ist.
\n\nEvent Bus: Eine einfache und flexible Implementierung
\n\nEin Event Bus ist ein zentraler Ereignisverteiler, der es ermöglicht, Ereignisse zu abonnieren und zu senden, ohne direktes Wissen über die Abonnenten zu haben. Wir implementieren ihn mit Generics und schwachen Referenzen, um Speicherlecks zu vermeiden.
\n\nBasisimplementierung des Event Bus
\n\nimport Foundation\n\n// Protokoll für alle Ereignisse\nprotocol Event { }\n\n// Konkrete Ereignistypen\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 Klasse\nfinal class EventBus {\n static let shared = EventBus()\n private init() {}\n \n // Wörterbuch zur Speicherung der Abonnenten\n private var subscribers = [ObjectIdentifier: [Any]]()\n \n // Abonnement eines Ereignisses\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 // Abbestellen aller Ereignisse für einen bestimmten Beobachter\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 // Veröffentlichen eines Ereignisses\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// Hilfsstruktur zur Speicherung der Abonnements\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\nVerwendung des Event Bus
\n\n// ViewController, der Ereignisse abonniert\nclass LoginViewController: UIViewController {\n \n override func viewDidLoad() {\n super.viewDidLoad()\n \n // Abonnieren des Ereignisses Auch in der Bibliothek
Express.js für JavaScript (Node.js): vollständiges Handbuch mit Beispielen
Reaktive Programmierung in Java: Die Reactor-Bibliothek
Dependency Injection Container für Swift (iOS/macOS): Swinject
Caching in C++: Redis, Memcached und integrierte Lösungen
Kryptographie in C++: Vollständiger Leitfaden zu Verschlüsselung und Hashing