NotificationCenter — essência, princípio de funcionamento e arquitetura de notificações

Autor: IT Sectr Publicado: 2026-03-18 Tempo de leitura: 10 min

NotificationCenter é um mecanismo do sistema no iOS para enviar e receber notificações entre componentes do aplicativo sem uma conexão direta entre remetente e destinatário. Baseado no padrão Observer, o NotificationCenter permite que objetos se inscrevam em eventos e respondam a eles de forma assíncrona. De acordo com a Apple Documentation (2025), o NSNotificationCenter suporta tanto o envio síncrono de notificações via post(name:object:) quanto o envio adiado via NotificationQueue. O centro de notificações opera dentro de um único processo e não cruza os limites dos aplicativos.

Principais pontos

  • NotificationCenter — uma implementação do padrão Observer para troca de eventos entre componentes iOS.
  • addObserver inscreve um objeto em notificações com um nome específico e objeto remetente.
  • post(name:object:) envia uma notificação a todos os observadores inscritos de forma síncrona.
  • removeObserver deve ser chamado no deinit, caso contrário ocorre um crash ao enviar a notificação.
  • NotificationQueue permite adiar notificações para entrega assíncrona.

O que é NotificationCenter?

NotificationCenter (NSNotificationCenter) é um mecanismo integrado do iOS para implementar comunicação fracamente acoplada entre objetos. O padrão Observer permite que um objeto (remetente) notifique vários outros objetos (observadores) sobre um evento sem uma referência direta a eles. O NotificationCenter opera com três entidades: Notification.Name (identificador de notificação), Notification (contêiner com dados) e NotificationCenter (despachante). Cada aplicativo tem um default center compartilhado.

NSNotification e Notification.Name

Notification.Name é uma estrutura que identifica o tipo de notificação. Criada via extension Name: Notification.Name(“MyNotification”). Notification é um objeto que contém name, object (remetente) e userInfo (dicionário com dados). As notificações do sistema são declaradas como constantes: UIApplication.didBecomeActiveNotification, UIResponder.keyboardWillShowNotification. Notificações personalizadas devem ser agrupadas via extension para evitar colisões de nomes. Os nomes devem ser de domínio reverso.

swift
// Definição de notificações personalizadas
extension Notification.Name {
    static let dataDidUpdate =
        Notification.Name("com.app.dataDidUpdate")
    static let userLoggedOut =
        Notification.Name("com.app.userLoggedOut")
}

// Envio de uma notificação com dados
let userInfo: [String: Any] = [
    "userId": 123,
    "timestamp": Date()
]
NotificationCenter.default.post(
    name: .dataDidUpdate,
    object: nil,
    userInfo: userInfo
)

Adicionar um observador (addObserver)

Um observador se inscreve em uma notificação através do método addObserver(_:selector:name:object:). Selector é o método que será chamado quando a notificação for recebida. O parâmetro object permite filtrar notificações de um remetente específico. Se object for nil, o observador recebe todas as notificações com o nome especificado de qualquer remetente. Desde o iOS 9, o addObserver não requer remoção manual para a API block-based, mas o selector-based ainda requer removeObserver.

swift
// Inscrição em uma notificação (baseada em selector)
NotificationCenter.default.addObserver(
    self,
    selector: #selector(handleDataUpdate),
    name: .dataDidUpdate,
    object: nil
)

@objc func handleDataUpdate(_ notification: Notification) {
    guard let userId = notification.userInfo?["userId"] as? Int else { return }
    updateUI(for: userId)
}

// Inscrição em uma notificação (baseada em bloco, iOS 9+)
var observer: NSObjectProtocol?
observer = NotificationCenter.default.addObserver(
    forName: .dataDidUpdate,
    object: nil,
    queue: .main
) { [weak self] notification in
    guard let self else { return }
    self.handleNotification(notification)
}

Como funciona o NotificationCenter?

O NotificationCenter armazena uma tabela de mapeamento (nome → conjunto de observadores). Quando o remetente chama post(name:object:), o centro de notificações percorre sincronamente todos os observadores inscritos nesse nome e chama seus seletores ou blocos. Característica chave: post bloqueia a thread atual até que todos os manipuladores concluam. Se os manipuladores realizam operações pesadas, isso atrasa o remetente. O NotificationQueue resolve esse problema adiando a entrega das notificações.

Envio síncrono (post)

O método post(name:object:userInfo:) envia uma notificação imediatamente a todos os observadores. A chamada é síncrona — o código após post executa somente após todos os manipuladores concluírem. A ordem de invocação dos observadores não é garantida e pode mudar entre execuções. Para processamento sequencial, use NotificationQueue com coalescing. Não chame post dentro de um manipulador da mesma notificação — isso leva à recursão infinita.

Envio adiado (NotificationQueue)

NotificationQueue adiciona notificações a uma fila para entrega assíncrona. Suporta coalescing (fusão de notificações idênticas) e seleção de fila de entrega (asap, idle, modal). O coalescing é útil para eventos frequentes (progresso de download) quando você precisa notificar apenas com o último valor. O NotificationQueue usa o run loop para disparar, portanto funciona apenas em threads com run loop ativo.

swift
// Envio adiado via NotificationQueue
let notification = Notification(
    name: .dataDidUpdate,
    object: self,
    userInfo: ["progress": 0.5]
)

// Coalescing: várias notificações são fundidas em uma
NotificationQueue.default.enqueue(
    notification,
    postingStyle: .whenIdle,
    coalesceMask: .onName,
    forModes: [.common]
)

// Entrega assíncrona via DispatchQueue
DispatchQueue.main.async {
    NotificationCenter.default.post(name: .dataDidUpdate, object: nil)
}

Notification vs Delegate vs KVO

O iOS fornece três mecanismos principais para comunicação entre objetos: NotificationCenter, Delegate e KVO (Key-Value Observing). Cada um resolve o problema de notificação, mas com diferentes compromissos em acoplamento, desempenho e segurança de tipos. A escolha do mecanismo depende da relação um-para-um ou um-para-muitos e da necessidade de transferência de dados.

CaracterísticaNotificationCenterDelegateKVO
AcoplamentoFraco (nome da notificação)Forte (protocolo)Médio (chave)
RelaçãoUm-para-muitosUm-para-umUm-para-muitos
Segurança de tiposBaixa (userInfo como Dictionary)Alta (métodos do protocolo)Média (Any?)
DesempenhoMédio (percurso da tabela)Alto (chamada direta)Baixo (NSObject)
AssincroniaSíncrono (post bloqueia)Síncrono na thread do remetenteSíncrono na alteração

Quando escolher NotificationCenter

NotificationCenter é ideal para eventos aos quais múltiplos componentes independentes precisam responder. Exemplos: alterações nas configurações do aplicativo, logout do usuário, recebimento de uma notificação push em segundo plano. NotificationCenter também é adequado para módulos fracamente acoplados (o recurso A não deve conhecer o recurso B). A desvantagem é a falta de segurança de tipos: as chaves do userInfo são strings, não enums.

Quando escolher Delegate ou KVO

Delegate é a escolha para relacionamentos um-para-um com um contrato claro (tableView.delegate). Delegate é mais rápido e seguro por tipos. KVO é a escolha para observar mudanças em uma propriedade específica do modelo (isLoading, progress). KVO requer herança de NSObject e pode causar dificuldades de depuração (strings mágicas como chaves). Em Swift moderno, Combine e sequências async substituem todas as três abordagens.

AddObserver: notificações síncronas e assíncronas

O método addObserver suporta duas variantes de inscrição: selector-based (tradicional) e block-based (com closure). Selector-based requer compatibilidade @objc e remoção manual do observador. Block-based (iOS 9+) permite usar uma capture list e é gerenciado automaticamente pelo SO ao usar blocos sem referências fortes. Block-based também suporta queue — o observador recebe a notificação na fila especificada.

addObserver baseado em selector

A forma tradicional de inscrição via selector. O método manipulador deve ser marcado com @objc e aceitar uma Notification opcional. Vantagem: pode ser usado por qualquer classe, incluindo Objective-C legado. Desvantagens: falta de segurança de tipos do selector, risco de erros de digitação no nome do selector, removeObserver obrigatório no deinit. Se o observador for removido antes do objeto, o manipulador não será chamado.

addObserver baseado em bloco

A API block-based aceita uma closure que executa ao receber a notificação. O parâmetro queue determina em qual fila o bloco executa — a fila principal para atualizações de UI ou uma fila em segundo plano para processamento de dados. O valor de retorno NSObjectProtocol é usado para remover o observador: NotificationCenter.default.removeObserver(observer). Block-based é preferível em Swift moderno.

swift
protocol NotificationToken {
    func dispose()
}

extension NotificationCenter {
    func observe(
        name: NSNotification.Name,
        object: Any? = nil,
        queue: OperationQueue? = .main,
        using block: @escaping (Notification) -> Void
    ) -> NotificationToken {
        let observer = addObserver(forName: name, object: object,
                                   queue: queue, using: block)
        return NotificationTokenWrapper(observer: observer, center: self)
    }
}

// Uso com remoção automática
class ViewModel {
    private var tokens: [NotificationToken] = []

    func startObserving() {
        let token = NotificationCenter.default.observe(
            name: .dataDidUpdate,
            queue: .main
        ) { [weak self] notification in
            self?.handleUpdate(notification)
        }
        tokens.append(token)
    }

    deinit {
        tokens.forEach { $0.dispose() }
    }
}

Gerenciamento de memória e remoção de observadores

Vazamentos de memória são um dos principais problemas ao trabalhar com NotificationCenter. Se um observador não for removido antes da desalocação, ao enviar uma notificação o centro tentará chamar um método em um objeto já desalocado, resultando em EXC_BAD_ACCESS. Desde o iOS 9, o block-based addObserver usa referências fracas, mas o selector-based ainda requer removeObserver manual. Melhor prática: remover o observador no deinit.

Quando chamar removeObserver

Selector-based: sempre chame NotificationCenter.default.removeObserver(self) no deinit. Se o observador estiver inscrito em várias notificações, você pode remover todas de uma vez (sem parâmetros) ou uma específica pelo nome. Block-based: remova via removeObserver com o token retornado pelo addObserver. Para block-based no iOS 9+, não ocorre vazamento, mas a remoção ainda é recomendada para desempenho: observadores desalocados não serão percorridos durante o post.

swift
class SafeObserver {
    private var observers: [NSObjectProtocol] = []

    func addSubscriptions() {
        let token1 = NotificationCenter.default.addObserver(
            forName: .dataDidUpdate, object: nil,
            queue: .main) { [weak self] _ in
            self?.refreshData()
        }
        let token2 = NotificationCenter.default.addObserver(
            forName: .userLoggedOut, object: nil,
            queue: .main) { [weak self] _ in
            self?.logout()
        }
        observers.append(contentsOf: [token1, token2])
    }

    deinit {
        observers.forEach { NotificationCenter.default.removeObserver($0) }
    }

    private func refreshData() { }
    private func logout() { }
}

Referências fracas através do padrão Token

O padrão Token automatiza o gerenciamento de observadores. Ao se inscrever, um objeto token (NSObjectProtocol) é retornado, que remove automaticamente o observador ao ser desalocado. NotificationTokenWrapper armazena uma referência fraca ao NotificationCenter e ao token do observador, chamando removeObserver no deinit. Isso aproxima o NotificationCenter da abordagem Combine, onde AnyCancellable gerencia o ciclo de vida da inscrição.

NotificationCenter em ambiente multithread

Segurança de threads: o NotificationCenter garante que post pode ser chamado de qualquer thread, e todos os observadores receberão a notificação na mesma thread onde post foi chamado. Isso é crítico para aplicações multithread: se uma notificação for enviada de uma thread em segundo plano, os manipuladores também executarão na thread em segundo plano. Para atualizações de UI, despache o tratamento para a fila principal via DispatchQueue.main.async.

Segurança de threads de post e addObserver

NotificationCenter é seguro para threads para chamadas post e addObserver de diferentes threads. A sincronização interna usa bloqueios, portanto posts frequentes de várias threads podem criar contenção. Para cenários de alta carga (progresso de download de 1000 arquivos), use uma fila de notificações separada ou um publisher Combine. NotificationQueue com postingStyle .now é equivalente a post direto.

Entrega assíncrona via Combine

NotificationCenter suporta publisher Combine via NotificationCenter.default.publisher(for:object:). Publisher transforma cada notificação em um evento Combine que pode ser transformado através de map, filter, debounce e throttle. Isso resolve o problema de entrega síncrona: o Combine processa notificações de forma assíncrona no Scheduler especificado. NotificationCenter.publisher é uma ponte entre o mecanismo legado e a programação reativa moderna.

swift
import Combine

class ReactiveViewModel {
    private var cancellables = Set<AnyCancellable>()

    func setupCombineSubscription() {
        NotificationCenter.default
            .publisher(for: .dataDidUpdate)
            .receive(on: DispatchQueue.main)
            .compactMap { $0.userInfo?["progress"] as? Float }
            .debounce(for: .seconds(0.3), scheduler: RunLoop.main)
            .sink { [weak self] progress in
                self?.progressLabel.text = "\(Int(progress * 100))%"
            }
            .store(in: &cancellables)
    }
}

Perguntas frequentes

NotificationCenter é seguro para threads?

Sim, NotificationCenter é seguro para threads para chamadas post e addObserver de qualquer thread. No entanto, os manipuladores executam na mesma thread onde post foi chamado. Para atualizações de UI, use queue: .main no block-based addObserver ou DispatchQueue.main.async dentro do manipulador. O publisher Combine com receive(on:) também resolve o problema de thread.

O que acontece se eu não remover o observador?

Selector-based: crash EXC_BAD_ACCESS ao enviar uma notificação após a desalocação do observador. Block-based (iOS 9+): sem vazamento graças à referência fraca, mas o centro de notificações continua mantendo o bloco na memória até removeObserver explícito. Recomenda-se sempre remover o observador no deinit ou usar o padrão Token para gerenciamento automático.

Qual a diferença entre NotificationCenter e KVO?

NotificationCenter é um mecanismo de transmissão para eventos arbitrários entre componentes não relacionados. KVO observa mudanças em uma propriedade específica de um objeto específico. KVO requer herança de NSObject e notifica automaticamente sobre mudanças de propriedade via setter. NotificationCenter notifica apenas quando post é chamado explicitamente. Para observação de modelo, KVO ou Combine é preferível.

Quantos NotificationCenter existem em um aplicativo?

Um default center por processo de aplicativo. Centros adicionais podem ser criados via NotificationCenter(), mas na prática o default compartilhado é usado. Cada centro opera independentemente — post em um não é entregue aos observadores de outro. Para isolamento de módulos, use namespaces Name separados através de nomes de notificação de domínio reverso.

Combine substitui o NotificationCenter?

Parcialmente. O Combine fornece NotificationCenter.Publisher, que envolve o NotificationCenter em um fluxo reativo. O Combine resolve o problema de sincronia (via receive(on:)), adiciona operadores de transformação e gerenciamento automático de inscrições (AnyCancellable). No entanto, o NotificationCenter permanece para notificações do sistema iOS (UIApplication, UIKeyboard) e código legado. Combine é um aprimoramento, não uma substituição.

Resumo

  • NotificationCenter — uma implementação do padrão Observer para comunicação fracamente acoplada um-para-muitos no iOS.
  • post envia uma notificação sincronamente a todos os observadores na thread atual, bloqueando o remetente.
  • addObserver suporta inscrição selector-based (com @objc) e block-based (com capture list e queue).
  • removeObserver é obrigatório no deinit para inscrições selector-based, caso contrário crash.
  • NotificationQueue fornece entrega adiada com coalescing para eventos frequentes.
  • Segurança de threads garante operação de qualquer thread, mas os manipuladores executam na thread do remetente.
  • Use o padrão Token ou o publisher Combine para gerenciamento de inscrições seguro e moderno.

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.

Discutir o projeto

Leia também