Combine: o que é, conceitos-chave e Publisher com Subscriber

Autor: IT Sectr Publicado: 2026-03-17 Tempo de leitura: 8 min

Combine é um framework de programação reativa da Apple, apresentado no iOS 13. De acordo com Apple Documentation, 2025, o Combine fornece uma API declarativa unificada para lidar com eventos assíncronos. Publisher define a fonte de dados, e Subscriber se inscreve para recebê-los.

Principais conclusões

  • Combine — um framework integrado da Apple para programação reativa, disponível desde o iOS 13
  • Publisher — um protocolo que define uma fonte de valores Output com possível erro Failure
  • Subscriber — um protocolo que recebe valores do Publisher com gerenciamento de demand
  • Subject — um Publisher que permite injeção manual de eventos (PassthroughSubject, CurrentValueSubject)
  • Operators — map, filter, combineLatest, flatMap para transformar e combinar fluxos

O que é Combine?

Combine é um framework declarativo Swift para processar eventos assíncronos ao longo do tempo. Ao contrário das abordagens baseadas em callbacks, o Combine permite descrever pipelines de processamento de dados através de uma cadeia de operadores. O framework está integrado com Foundation (URLSession, Timer, NotificationCenter) e SwiftUI (ObservableObject, @Published).

Protocolo Publisher

Qualquer tipo que implemente o protocolo Publisher deve definir Output (tipo de valores) e Failure (tipo de erro). Um Publisher não está ativo até ser inscrito — ele começa a emitir eventos apenas após a chamada de subscribe. Esta é uma semântica fria, característica de streams reativos, melhorando a eficiência.

Protocolo Subscriber

Subscriber recebe eventos através de três métodos: receive(subscription:) — confirmação da inscrição com gerenciamento de demand; receive(_:) — recebimento de um novo valor; receive(completion:) — conclusão do fluxo com sucesso ou erro. Demand especifica quantos valores o Subscriber está pronto para aceitar — este é o mecanismo de backpressure.

Publishers integrados

A Apple fornece muitos Publishers integrados: Just emite um único valor e finaliza, Future — um resultado assíncrono com um closure, Deferred — criação adiada de um Publisher até a inscrição. URLSession.dataTaskPublisher converte uma requisição de rede em um stream reativo. Timer.publish cria um temporizador periódico. NotificationCenter.default.publisher transforma notificações em um Publisher. Essas integrações permitem assinar eventos sem ponte manual.

Publisher e Subscriber no Combine

No Combine, Publisher e Subscriber estão conectados através do protocolo Subscription. Subscription é um objeto de conexão que controla o fluxo de dados. Os desenvolvedores não precisam criar seus próprios tipos Publisher — a Apple fornece tipos integrados: Just, Future, Deferred, Fail, Empty, além de Publishers para URLSession e Timer.

Subject no Combine

Subject é um Publisher no qual valores podem ser enviados manualmente. PassthroughSubject não armazena estado: um assinante só recebe eventos que ocorreram após a assinatura. CurrentValueSubject, semelhante ao BehaviorRelay no RxSwift, armazena o valor atual e o transmite imediatamente para novos assinantes.

Backpressure

O mecanismo de backpressure no Combine regula a velocidade de transferência de dados. O Subscriber informa ao Publisher através de subscription.request(.unlimited) ou subscription.request(.max(N)) quantos valores está pronto para processar. Isso evita o transbordamento do buffer quando as velocidades do produtor e consumidor são desiguais.

Operadores do Combine

O Combine inclui mais de 100 operadores, divididos em categorias: transformação (map, tryMap, flatMap), filtragem (filter, compactMap, removeDuplicates), combinação (combineLatest, merge, zip), gerenciamento de tempo (debounce, throttle, delay) e tratamento de erros (catch, replaceError, retry).

O operador combineLatest combina os últimos valores de dois Publishers — cada vez que um deles emite um novo valor, o closure é chamado com ambos os valores atualizados. Este operador é indispensável para validação de formulários onde é necessário rastrear o estado de vários campos de entrada simultaneamente.

O operador debounce atrasa a publicação de valores até que um intervalo especificado passe sem novos eventos. Isso é crítico para campos de busca: a requisição ao servidor é enviada somente após o usuário parar de digitar por 300–500 ms, reduzindo a carga em 5 a 10 vezes.

Tratamento de erros

O Combine oferece várias estratégias de tratamento de erros no nível dos operadores. catch intercepta Failure e substitui o Publisher por um alternativo — o fluxo continua sem travar. replaceError(with:) fornece um valor padrão em vez do erro. retry(_:) tenta a inscrição novamente um número especificado de vezes em caso de falha. Importante: um tipo de erro Never na assinatura do Publisher garante que o fluxo nunca terminará com erro — isso permite usar Publisher no SwiftUI sem tratamento de Failure.

Exemplos de código Combine

O primeiro exemplo mostra o uso básico do Just — um Publisher que emite um único valor e finaliza:

swift
let publisher = Just("Hello Combine")

publisher
    .sink(receiveCompletion: { completion in
        print("Concluído: \(completion)")
    }, receiveValue: { value in
        print("Recebido: \(value)")
    })

O segundo exemplo demonstra a integração do Combine com URLSession para uma requisição de rede com processamento do resultado na thread principal:

swift
let url = URL(string: "https://api.example.com")!

URLSession.shared
    .dataTaskPublisher(for: url)
    .map { $0.data }
    .receive(on: DispatchQueue.main)
    .sink(receiveCompletion: { completion in
        if case .failure(let error) = completion {
            print("Erro: \(error)")
        }
    }, receiveValue: { data in
        print("Dados recebidos: \(data.count)")
    })

O terceiro exemplo mostra o uso de CurrentValueSubject para gerenciamento de estado:

swift
let counter = CurrentValueSubject<Int, Never>(0)

counter
    .sink { value in
        print("Contador: \(value)")
    }

counter.send(1) // Imprime: Contador: 1
counter.send(2) // Imprime: Contador: 2
print(counter.value) // Imprime: 2

Combine vs RxSwift

Combine e RxSwift resolvem o mesmo problema — programação reativa — mas com abordagens diferentes. Combine é um framework nativo da Apple integrado ao sistema: não requer instalação de dependências, integrado com SwiftUI e Foundation. RxSwift é uma biblioteca de terceiros com suporte ao iOS 9+ e um conjunto mais amplo de operadores.

O desempenho do Combine é superior em cenários típicos graças à implementação nativa em C. RxSwift fornece mais ferramentas de depuração (RxSwift.Resources.total, Debug), mas sua arquitetura orientada a objetos pode ser menos eficiente em grandes fluxos de dados. A escolha entre eles é um compromisso entre capacidades e integração.

Uma diferença importante é o modelo de backpressure. No Combine, o Subscriber gerencia a demand através de Subscription, dando controle explícito sobre a velocidade do fluxo. No RxSwift, a backpressure não é controlada por padrão — Observable emite todos os valores, e Subscriber os processa à medida que chegam. Para grandes fluxos de dados, o Combine é mais previsível e seguro em termos de memória.

Combine é profundamente integrado com SwiftUI no nível da linguagem. @Published gera um Publisher, ObservableObject fornece objectWillChange Publisher. SwiftUI View assina automaticamente esses Publishers e redesenha nas mudanças. Para UIKit existem wrappers de terceiros como CombineCocoa, mas o Combine foi originalmente projetado para SwiftUI, portanto sua integração no UIKit requer código adicional. RxSwift, por outro lado, possui um ecossistema rico para UIKit: RxCocoa fornece wrappers reativos para todos os elementos de UI.

Combine suporta integração com Core Data através de NSFetchedResultsController Publisher. O Publisher emite novos dados a cada mudança na pilha Core Data: adicionar, excluir, atualizar registros. Isso permite construir listas reativas sem chamar reloadData manualmente. Combinando Combine com NotificationCenter Publisher para UIApplication.willResignActiveNotification, os desenvolvedores criam uma camada reativa para todo o ciclo de vida da aplicação sem delegates e callbacks. Para classes ObservableObject, SwiftUI atualiza automaticamente a View quando propriedades @Published mudam — Combine gerencia toda a cadeia sem uma única linha de código manual. O teste unitário do código Combine é feito através de XCTestExpectation e Publisher.sink em casos de teste com isolamento de Scheduler via ImmediateScheduler.

Ao trabalhar com Combine em projetos UIKit, os desenvolvedores frequentemente assinam através de sink e armazenam AnyCancellable em um Set. Padrão típico: ViewController cria uma view, armazena cancellables, assina o Publisher do ViewModel. No deinit, todas as assinaturas são automaticamente canceladas através da coleção Cancellables. Para o manuseio adequado de UIControl no Combine, você pode usar UIControl.Event Publisher através da extensão publisher(for:).

A depuração do Combine é feita através do operador print() ou handleEvents(). print(String) registra todos os eventos: receive subscription, request demand, receive value, receive completion. handleEvents fornece um controle mais refinado: você pode especificar closures para cada estágio do ciclo de vida do Publisher. Para testes, existe CombineExpectations — uma biblioteca que permite verificar se um Publisher emite os valores esperados em testes com tempo virtual e controle de demand.

Combine na prática

Combine é usado ativamente no SwiftUI para gerenciamento de formulários: cada propriedade @Published gera um Publisher, SwiftUI assina ele através de View.body. Combinando vários Publishers via combineLatest, a validação de formulários se torna declarativa: cada Publisher rastreia um campo, combineLatest coleta todos os valores, map os valida e retorna o status do botão Submit. Publishers.Merge combina vários Publishers do mesmo tipo em um único — útil para coletar eventos de diferentes controles em um único fluxo.

Para integração do Combine com UIKit, use UIControl Publisher através de uma extensão: button.publisher(for: .touchUpInside) retorna um Publisher que emite um evento ao toque. CombineCocoa é uma biblioteca da comunidade que fornece Publishers para todos os eventos UIControl, UITextView.text, UIScrollView.contentOffset. Ao cancelar a assinatura, o Store de cancellables é limpo no deinit, garantindo que nenhuma assinatura sobreviva ao seu proprietário. Para UIControl com múltiplos estados, use Publishers.MergeMany para combinar Publishers em um array.

Perguntas frequentes

A partir de qual versão do iOS o Combine está disponível?

Combine está disponível desde o iOS 13, macOS 10.15, tvOS 13 e watchOS 6. Isso limita seu uso em projetos que exigem suporte para versões mais antigas. Para iOS 12 e anteriores, utiliza-se RxSwift ou bibliotecas de terceiros.

Qual a diferença entre PassthroughSubject e CurrentValueSubject?

PassthroughSubject não armazena estado e não repete o último valor para novos assinantes — eles só recebem eventos futuros. CurrentValueSubject armazena o valor atual e o transmite imediatamente para novos assinantes. CurrentValueSubject.value permite ler e escrever o valor atual de forma síncrona.

Como o Combine se integra com o SwiftUI?

Combine está no centro do SwiftUI: @Published gera um Publisher, ObservableObject usa objectWillChange Publisher. SwiftUI View assina automaticamente @ObservedObject e @StateObject através do pipeline Combine, redesenhand a View quando as propriedades mudam.

O que é backpressure no Combine?

Backpressure é um mecanismo para controlar a velocidade de transferência de dados. O Subscriber informa à Subscription quantos valores está pronto para processar (demand). O Publisher não pode emitir mais do que o solicitado. Isso é crítico ao trabalhar com grandes fluxos de dados de sockets de rede.

Como tratar erros no Combine?

O operador catch intercepta um erro e substitui o Publisher por um alternativo. replaceError substitui o erro por um valor padrão. retry tenta a inscrição novamente um número especificado de vezes em caso de erro. Todos os operadores devem ser colocados antes de subscribe para evitar travamentos em caso de Failure.

Resumo

  • Combine — um framework integrado da Apple para programação reativa desde o iOS 13
  • Publisher — um protocolo com Output e Failure, começa a funcionar após assinatura
  • Subscriber — recebe valores via receive com suporte a gerenciamento de demand
  • Subject (PassthroughSubject, CurrentValueSubject) — Publisher com injeção manual de eventos
  • Operadores map, filter, combineLatest, debounce, catch — a base dos pipelines
  • Backpressure via demand evita o transbordamento do buffer do Subscriber
  • Escolha Combine para novos projetos com iOS 13+, RxSwift para suporte a versões antigas

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