Event Bus y el patrón Observer en Swift: implementación y ejemplos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Event Bus y el patrón Observer en Swift (iOS/macOS)



En el desarrollo para iOS y macOS, a menudo surge la necesidad de organizar una interacción débilmente acoplada entre los componentes de la aplicación. El patrón Observer y su implementación como Event Bus (bus de eventos) es una herramienta poderosa para resolver esta tarea. En este artículo, analizaremos en detalle cómo implementar un Event Bus en Swift, utilizando las capacidades modernas del lenguaje (Generics, closures, weak references).



¿Qué es el patrón Observer?



El patrón Observer (Observador) define una relación de "uno a muchos" entre objetos. Cuando un objeto (editor) cambia su estado, todos los objetos que dependen de él (suscriptores) son notificados y actualizados automáticamente. Esto permite evitar un acoplamiento rígido y simplifica el mantenimiento del código.



En Swift, las implementaciones nativas de Observer son:

  • NotificationCenter — un bus de notificaciones global, integrado en Foundation.
  • Key-Value Observing (KVO) — un mecanismo para observar las propiedades de los objetos.
  • Combine framework (iOS 13+) — un framework reactivo con soporte para editores y suscriptores.


Sin embargo, a menudo se requiere una implementación más ligera y type-safe, especialmente al trabajar con código legacy o en proyectos donde Combine no está disponible.



Event Bus: una implementación simple y flexible



Event Bus es un despachador central de eventos que permite suscribirse a eventos y enviarlos sin conocimiento directo de los suscriptores. Lo implementaremos usando genéricos y referencias débiles para evitar fugas de memoria.



Implementación básica de Event Bus



import Foundation

// Protocolo para todos los eventosprotocol Event { }

// Tipos de eventos concretosstruct UserLoggedInEvent: Event { let userId: String let userName: String}

struct DataLoadedEvent: Event { let data: [String]}

// Clase Event Busfinal class EventBus { static let shared = EventBus() private init() {} // Diccionario para almacenar suscriptores private var subscribers = [ObjectIdentifier: [Any]]() // Suscripción a un evento func subscribe<T: Event>(observer: AnyObject, handler: @escaping (T) -> Void) { let key = ObjectIdentifier(T.self) let wrapped = Subscription(observer: observer, handler: handler as Any) if subscribers[key] != nil { subscribers[key]?.append(wrapped) } else { subscribers[key] = [wrapped] } } // Cancelar suscripción de todos los eventos para un observador específico func unsubscribe(observer: AnyObject) { for key in subscribers.keys { subscribers[key]?.removeAll(where: { subscription in if let sub = subscription as? Subscription { return sub.observer === observer } return false }) } } // Publicar un evento func publish<T: Event>(event: T) { let key = ObjectIdentifier(T.self) guard let subs = subscribers[key] else { return } for subscription in subs { if let sub = subscription as? Subscription { if let handler = sub.handler as? (T) -> Void { handler(event) } } } }}

// Estructura auxiliar para almacenar suscripcionesprivate struct Subscription { weak var observer: AnyObject? let handler: Any init(observer: AnyObject, handler: Any) { self.observer = observer self.handler = handler }}


Uso de Event Bus



// ViewController que se suscribe a eventosclass LoginViewController: UIViewController {        override func viewDidLoad() {        super.viewDidLoad()                // Nos suscribimos al evento                    

Recommendations