Observer — um padrão comportamental no qual um objeto (o publicador) notifica múltiplos subscritores sobre mudanças no seu estado. No desenvolvimento móvel, Observer é a base dos mecanismos reativos: a UI subscreve as alterações de dados e atualiza-se automaticamente. O padrão está implementado no NotificationCenter no iOS e no LiveData/Flow no Android. Mais detalhes em Refactoring Guru: Observer.
Pontos principais
Observer — um padrão comportamental GoF que define uma dependência um-para-muitos entre objetos. Quando um objeto (Subject ou Observable) muda o seu estado, todos os objetos dependentes (Observers) são automaticamente notificados e atualizados. O padrão implementa acoplamento fraco: o publicador não conhece as classes específicas dos subscritores — apenas que implementam a interface Observer.
Estrutura do Observer inclui a interface Subject com os métodos attach(), detach(), notify() e a interface Observer com o método update(). ConcreteSubject armazena o estado e a lista de subscritores. ConcreteObserver implementa update() e reage às mudanças. No desenvolvimento móvel, a implementação clássica do GoF é rara — é substituída por mecanismos integrados: NotificationCenter, Combine, Flow, LiveData, que implementam a mesma ideia com APIs modernas.
Modelo Push vs Pull — no modelo Push, o Subject envia dados a todos os subscritores (NotificationCenter.post). No modelo Pull, o Subject apenas notifica, e o subscritor solicita os dados por si próprio. Android LiveData usa Push (os dados são passados no observe()), RxJava/Flow suportam ambos os modelos. A escolha depende da tarefa: Push é mais simples para atualizações de UI, Pull é mais eficiente para grandes volumes de dados que o subscritor pode não querer receber.
NotificationCenter — um mecanismo integrado do iOS/macOS para implementar Observer. O publicador envia uma Notification através de NotificationCenter.default.post(name:, object:, userInfo:). O subscritor regista-se através de addObserver(forName:, queue:, using:). NotificationCenter suporta notificações nomeadas (Notification.Name) e pode passar qualquer dados no userInfo. UIKeyboardWillShowNotification, UIApplicationDidEnterBackgroundNotification — exemplos do sistema.
extension Notification.Name {
static let userDidLogin = Notification.Name("userDidLogin")
}
// Publicador
NotificationCenter.default.post(
name: .userDidLogin,
object: nil,
userInfo: ["userId": "123"]
)
// Subscritor
class ProfileViewModel {
private var observers: [NSObjectProtocol] = []
func startObserving() {
let observer = NotificationCenter.default.addObserver(
forName: .userDidLogin,
object: nil,
queue: .main
) { [weak self] notification in
guard let userId = notification.userInfo?["userId"] as? String else { return }
// O subscritor reage ao evento
self?.loadProfile(userId: userId)
}
observers.append(observer)
}
func stopObserving() {
observers.forEach { NotificationCenter.default.removeObserver($0) }
observers.removeAll()
}
}
Framework Combine — uma alternativa reativa moderna ao NotificationCenter, introduzida no iOS 13. Publisher (NotificationCenter, URLSession, Timer) — o publicador, Subscriber (sink, assign) — o subscritor. Combine adiciona operadores (map, filter, combineLatest) para transformação de fluxos de dados. @Published — um property wrapper que notifica automaticamente os subscritores sobre alterações. No MVVM com SwiftUI, Combine substitui o NotificationCenter para ligar ViewModel e View.
KVO (Key-Value Observing) — um mecanismo antigo do ObjC/Swift para observar propriedades individuais de objetos. @objc dynamic var name: String — uma propriedade observável. observe(.name) — subscrição. KVO funciona apenas com classes compatíveis com @objc e herança do ObjC. A Apple recomenda Combine e @Published em vez de KVO em novos projetos. KVO continua relevante para compatibilidade com UIKit em projetos híbridos.
LiveData — um componente do Android Architecture Components para implementar Observer. Uma classe observável que notifica os subscritores sobre alterações de dados. LiveData tem consciência do ciclo de vida: os subscritores (LifecycleOwner) cancelam automaticamente a subscrição quando são destruídos. LiveData usa o modelo Push: os dados são passados no observe(). LiveData é o bloco de construção básico do MVVM no Android antes do Jetpack Compose.
// ViewModel — publicador
class UserViewModel : ViewModel() {
private val _user = MutableLiveData<User?>(null)
val user: LiveData<User?> = _user
fun loadUser(id: String) {
viewModelScope.launch {
val result = userRepository.getUser(id)
_user.value = result
}
}
}
// Fragment — subscritor
class UserFragment : Fragment() {
private val viewModel: UserViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.user.observe(viewLifecycleOwner) { user ->
// O subscritor reage às alterações
userName.text = user?.name
userEmail.text = user?.email
}
}
}
StateFlow e SharedFlow — tipos reativos do Kotlin Coroutines que substituíram o LiveData no Jetpack Compose. StateFlow — um contentor de estado observável com um valor atual fixo. SharedFlow — um fluxo hot configurável sem estado, adequado para eventos únicos (navegação, toasts). Ambos os tipos estão estreitamente integrados com o Compose: collectAsState(), collectAsEffect(). StateFlow é obrigatório em projetos Android modernos com Compose.
LiveData vs StateFlow — LiveData está ligado ao ciclo de vida do Android, StateFlow é independente da plataforma. StateFlow suporta corrotinas, operadores (map, filter) e pode ser testado sem dependências do Android. LiveData é mais simples para compatibilidade com Java. A Google recomenda StateFlow para novos projetos em Kotlin + Compose, LiveData para manter projetos legados ou código Java.
Fugas de memória — o principal problema do Observer sem uma gestão adequada de subscrições. Se um subscritor (Activity, Fragment, UIViewController) for destruído mas a subscrição não for cancelada, o publicador continua a manter uma referência para ele e o coletor de lixo não consegue libertar a memória. No Android, LifecycleOwner (Activity/Fragment) deve chamar removeObserver() ou usar observe(viewLifecycleOwner). No iOS — removeObserver no deinit ou disposeBag no Combine.
| Plataforma | Mecanismo Observer | Cancelamento automático | Cancelamento manual |
|---|---|---|---|
| iOS | NotificationCenter | Não | removeObserver() no deinit |
| iOS | Combine (sink) | Não | store(in: &bag) — DisposeBag |
| iOS | KVO | Não | removeObserver() no deinit |
| Android | LiveData | Sim (LifecycleOwner) | removeObserver() opcional |
| Android | StateFlow | Através de viewModelScope | cancel() Job ao cancelar |
| Android | RxJava | Não | dispose() no CompositeDisposable |
Referência fraca em subscritores — ao usar closures em blocos de subscrição, use [weak self] em Swift e referencie o âmbito do ciclo de vida em Kotlin. LiveData gere automaticamente as subscrições através de LifecycleOwner — a subscrição está ativa apenas quando o Lifecycle está no estado STARTED ou RESUMED. StateFlow no Compose usa collectAsState() com consciência do ciclo de vida. NotificationCenter no iOS requer [weak self] explícito porque o closure mantém uma referência forte a self.
Observer (GoF) e Publicador-Subscritor (PubSub) — padrões semelhantes mas diferentes. No Observer, o publicador notifica diretamente os subscritores chamando os seus métodos. O publicador conhece os subscritores (armazena uma lista). No PubSub, o publicador e o subscritor não se conhecem — um mediador (Event Bus, Message Queue, NotificationCenter) está entre eles. O publicador envia uma mensagem para um canal, o subscritor ouve o canal. PubSub tem um acoplamento mais fraco.
Exemplos de PubSub no desenvolvimento móvel — NotificationCenter no iOS pode ser considerado PubSub: o publicador não conhece os subscritores — ele simplesmente publica uma notificação. EventBus ou Otto no Android (obsoletos). SharedFlow com BroadcastChannel — PubSub no mundo Kotlin. Em sistemas distribuídos, PubSub é implementado através de RabbitMQ, Kafka, Google PubSub. Para desenvolvimento móvel, PubSub é útil em arquitetura modular onde os módulos não devem depender uns dos outros.
O que escolher — para atualizações de UI (ViewModel → View), use Observer (LiveData, StateFlow, @Published). Para eventos entre módulos (autenticação, saída de sessão, mudança de tema) — PubSub (SharedFlow, NotificationCenter, EventBus). Observer é mais simples e eficiente dentro de um único ecrã, PubSub é mais flexível para eventos globais mas mais difícil de depurar devido a dependências implícitas.
Perguntas frequentes
StateFlow é um tipo independente de plataforma do Kotlin Coroutines, enquanto LiveData está ligado ao ciclo de vida do Android. StateFlow suporta corrotinas e operadores, e pode ser testado sem Android. LiveData gere automaticamente as subscrições através de LifecycleOwner. A Google recomenda StateFlow para novos projetos em Kotlin + Compose, e LiveData para compatibilidade com Java.
Use [weak self] no closure do manipulador e chame removeObserver() no deinit. Armazene uma referência ao observer (NSObjectProtocol) e remova-a quando o objeto for destruído. No Combine, use AnyCancellable e store(in:) para cancelamento automático ao libertar o DisposeBag.
Sim, o SwiftUI suporta ObservableObject com @Published e @StateObject/@ObservedObject — esta é uma implementação integrada do Observer. @Published notifica automaticamente a View sobre alterações. Combine não é necessário: ObservableObject usa o Publisher objectWillChange incorporado no SwiftUI. Combine adiciona operadores para transformação de fluxos.
SharedFlow — para eventos únicos (navegação, toasts, Snackbar) onde não é necessário um valor atual. StateFlow — para estado da UI (lista de dados, progresso de carregamento) onde é necessária uma imagem instantânea atual. SharedFlow não tem propriedade value e não devolve o último valor a novos subscritores.
KVO é um mecanismo legado do ObjC, requer @objc dynamic e funciona apenas com classes herdadas de NSObject. Combine é um framework moderno do Swift, type-safe, com operadores e integração com SwiftUI. Combine substitui KVO e NotificationCenter. A Apple recomenda Combine para novos projetos, KVO apenas para suporte legado.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também