Event Bus e padrão Observer em Swift: implementação e exemplos

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Event Bus e padrão Observer em Swift (iOS/macOS)



No desenvolvimento para iOS e macOS, frequentemente surge a necessidade de organizar uma interação fracamente acoplada entre os componentes do aplicativo. O padrão Observer e sua implementação na forma de Event Bus (barramento de eventos) é uma ferramenta poderosa para resolver esse problema. Neste artigo, vamos detalhar como implementar um Event Bus em Swift, usando recursos modernos da linguagem (Generics, closures, weak references).



O que é o padrão Observer?



O padrão Observer (Observador) define uma relação "um para muitos" entre objetos. Quando um objeto (publicador) altera seu estado, todos os objetos dependentes (assinantes) são automaticamente notificados e atualizados. Isso evita o acoplamento rígido e simplifica a manutenção do código.



Em Swift, as implementações nativas do Observer são:

  • NotificationCenter — um barramento global de notificações, embutido no Foundation.
  • Key-Value Observing (KVO) — um mecanismo para observar propriedades de objetos.
  • Combine framework (iOS 13+) — um framework reativo com suporte a publicadores e assinantes.


No entanto, muitas vezes é necessária uma implementação mais leve e type-safe, especialmente ao trabalhar com código legado ou em projetos onde o Combine não está disponível.



Event Bus: uma implementação simples e flexível



Event Bus é um despachante central de eventos que permite assinar e enviar eventos sem conhecimento direto sobre os assinantes. Nós o implementaremos usando genéricos e referências fracas para evitar vazamentos de memória.



Implementação básica do Event Bus



import Foundation

// Protocolo para todos os eventosprotocol Event { }

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

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

// Classe Event Busfinal class EventBus { static let shared = EventBus() private init() {} // Dicionário para armazenar assinantes private var subscribers = [ObjectIdentifier: [Any]]() // Assinar um 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 a assinatura de todos os eventos para um 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 um 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) } } } }}

// Estrutura auxiliar para armazenar assinaturasprivate struct Subscription { weak var observer: AnyObject? let handler: Any init(observer: AnyObject, handler: Any) { self.observer = observer self.handler = handler }}


Usando o Event Bus



// ViewController que assina eventosclass LoginViewController: UIViewController {        override func viewDidLoad() {        super.viewDidLoad()                // Assinamos o evento                    

Recommendations