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

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 a través de un bus de eventos (Event Bus) son una herramienta poderosa para crear una arquitectura flexible y escalable. En este artículo, analizaremos cómo implementar un Event Bus en Swift, lo compararemos con los mecanismos integrados de Apple (NotificationCenter, Combine) y mostraremos ejemplos prácticos para iOS/macOS.



¿Qué es Event Bus y el patrón Observer?



El patrón Observer define una relación de "uno a muchos" entre objetos: cuando un objeto (el publicador) cambia su estado, todos los objetos dependientes (los suscriptores) son notificados automáticamente.



Event Bus (bus de eventos) es un mecanismo centralizado que permite a cualquier componente enviar eventos (publicar) y recibirlos (suscribirse) sin conocerse directamente entre sí. Esto implementa el principio de acoplamiento débil (loose coupling).



En el ecosistema de Apple ya existen soluciones integradas:

  • NotificationCenter — una implementación clásica de Observer, pero con limitaciones en cuanto a tipificación y seguridad.
  • Combine — un framework moderno para programación reactiva que proporciona potentes Publisher/Subscriber.

Sin embargo, un Event Bus personalizado brinda control total y puede integrarse más fácilmente en proyectos heredados (legacy).



Implementación de un Event Bus simple en Swift



Crearemos un bus de eventos universal utilizando genéricos y referencias débiles para prevenir fugas de memoria.



import Foundation

// Protocolo para eventosprotocol Event { }

// Implementación de Event Busfinal class EventBus { static let shared = EventBus() private var observers = [ObjectIdentifier: [WeakObserver]]() private init() { } // Suscripción a un evento func subscribe<T: Event>(observer: AnyObject, handler: @escaping (T) -> Void) { let id = ObjectIdentifier(T.self) let weakRef = WeakObserver(observer: observer, handler: { event in guard let castedEvent = event as? T else { return } handler(castedEvent) }) if observers[id] != nil { observers[id]?.append(weakRef) } else { observers[id] = [weakRef] } // Limpiar referencias muertas cleanDeadObservers(for: id) } // Publicación de un evento func publish<T: Event>(_ event: T) { let id = ObjectIdentifier(T.self) guard let observerList = observers[id] else { return } for weakObserver in observerList { weakObserver.handler?(event) } // Eliminar objetos liberados cleanDeadObservers(for: id) } // Cancelar suscripción func unsubscribe(observer: AnyObject, eventType: Event.Type) { let id = ObjectIdentifier(eventType) observers[id]?.removeAll { $0.observer === observer } } private func cleanDeadObservers(for id: ObjectIdentifier) { observers[id]?.removeAll { $0.observer == nil } }}

// Clase auxiliar para referencia débilprivate class WeakObserver { weak var observer: AnyObject? var handler: ((Event) -> Void)? init(observer: AnyObject, handler: @escaping (Event) -> Void) { self.observer = observer self.handler = handler }}


Ejemplo de uso



Definamos eventos personalizados:



struct UserLoggedInEvent: Event {    let userId: String    let userName: String}

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


Uso en un ViewController:



class ProfileViewController: UIViewController {    override func                    

Recommendations