Event Bus und das Observer-Pattern in Swift: Implementierung und Beispiele

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Event Bus und das Observer-Pattern in Swift (iOS/macOS)

\n\n

Bei 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\n

Was ist das Observer-Pattern?

\n\n

Das 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\n

In 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
\n\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\n

Event Bus: Eine einfache und flexible Implementierung

\n\n

Ein 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\n

Basisimplementierung des Event Bus

\n\n
import 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\n

Verwendung 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                    

Empfehlungen