Combine: qué es, conceptos clave y Publisher con Subscriber

Autor: IT Sectr Publicado: 2026-03-17 Tiempo de lectura: 8 min

Combine es un framework de programación reactiva de Apple, presentado en iOS 13. Según Apple Documentation, 2025, Combine proporciona una API declarativa unificada para el manejo de eventos asíncronos. Publisher define la fuente de datos, y Subscriber se suscribe para recibirlos.

Puntos clave

  • Combine — un framework integrado de Apple para programación reactiva, disponible desde iOS 13
  • Publisher — un protocolo que define una fuente de valores Output con un posible error Failure
  • Subscriber — un protocolo que recibe valores del Publisher con gestión de demand
  • Subject — un Publisher que permite la inserción manual de eventos (PassthroughSubject, CurrentValueSubject)
  • Operators — map, filter, combineLatest, flatMap para transformar y combinar flujos

¿Qué es Combine?

Combine es un framework declarativo de Swift para procesar eventos asíncronos en el tiempo. A diferencia de los enfoques basados en callbacks, Combine permite describir pipelines de procesamiento de datos a través de una cadena de operadores. El framework está integrado con Foundation (URLSession, Timer, NotificationCenter) y SwiftUI (ObservableObject, @Published).

Protocolo Publisher

Cualquier tipo que implemente el protocolo Publisher debe definir Output (tipo de valores) y Failure (tipo de error). Un Publisher no está activo hasta que se suscribe — comienza a emitir eventos solo después de llamar a subscribe. Esta es una semántica fría, característica de los streams reactivos, que mejora la eficiencia.

Protocolo Subscriber

Subscriber recibe eventos a través de tres métodos: receive(subscription:) — confirmación de suscripción con gestión de demand; receive(_:) — recepción de un nuevo valor; receive(completion:) — finalización del flujo con éxito o error. Demand especifica cuántos valores está listo para aceptar el Subscriber — este es el mecanismo de backpressure.

Publishers integrados

Apple proporciona muchos Publishers integrados: Just emite un solo valor y finaliza, Future — un resultado asíncrono con un closure, Deferred — creación diferida de un Publisher hasta la suscripción. URLSession.dataTaskPublisher convierte una solicitud de red en un stream reactivo. Timer.publish crea un temporizador periódico. NotificationCenter.default.publisher convierte notificaciones en un Publisher. Estas integraciones permiten suscribirse a eventos sin puente manual.

Publisher y Subscriber en Combine

En Combine, Publisher y Subscriber están conectados a través del protocolo Subscription. Subscription es un objeto de conexión que controla el flujo de datos. Los desarrolladores no necesitan crear sus propios tipos Publisher — Apple proporciona los integrados: Just, Future, Deferred, Fail, Empty, así como Publishers para URLSession y Timer.

Subject en Combine

Subject es un Publisher en el que se pueden enviar valores manualmente. PassthroughSubject no almacena estado: un suscriptor solo recibe eventos que ocurrieron después de la suscripción. CurrentValueSubject, similar a BehaviorRelay en RxSwift, almacena el valor actual y lo transmite inmediatamente a nuevos suscriptores.

Backpressure

El mecanismo de backpressure en Combine regula la velocidad de transferencia de datos. El Subscriber informa al Publisher a través de subscription.request(.unlimited) o subscription.request(.max(N)) cuántos valores está listo para procesar. Esto evita el desbordamiento del búfer cuando las velocidades del productor y consumidor son desiguales.

Operadores de Combine

Combine incluye más de 100 operadores, divididos en categorías: transformación (map, tryMap, flatMap), filtrado (filter, compactMap, removeDuplicates), combinación (combineLatest, merge, zip), gestión del tiempo (debounce, throttle, delay) y manejo de errores (catch, replaceError, retry).

El operador combineLatest combina los últimos valores de dos Publishers — cada vez que uno de ellos emite un nuevo valor, el closure se llama con ambos valores actualizados. Este operador es indispensable para la validación de formularios donde se necesita rastrear el estado de múltiples campos de entrada simultáneamente.

El operador debounce retrasa la publicación de valores hasta que pase un intervalo especificado sin nuevos eventos. Esto es crítico para los campos de búsqueda: la solicitud al servidor se envía solo después de que el usuario deja de escribir durante 300–500 ms, reduciendo la carga entre 5 y 10 veces.

Manejo de errores

Combine ofrece varias estrategias de manejo de errores a nivel de operadores. catch intercepta Failure y reemplaza el Publisher por uno de respaldo — el flujo continúa sin caerse. replaceError(with:) proporciona un valor por defecto en lugar del error. retry(_:) reintenta la suscripción un número especificado de veces ante una falla. Es importante: un tipo de error Never en la firma del Publisher garantiza que el flujo nunca terminará con error — esto permite usar Publisher en SwiftUI sin manejo de Failure.

Ejemplos de código Combine

El primer ejemplo muestra el uso básico de Just — un Publisher que emite un solo valor y finaliza:

swift
let publisher = Just("Hello Combine")

publisher
    .sink(receiveCompletion: { completion in
        print("Completado: \(completion)")
    }, receiveValue: { value in
        print("Recibido: \(value)")
    })

El segundo ejemplo demuestra la integración de Combine con URLSession para una solicitud de red con procesamiento del resultado en el hilo 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("Error: \(error)")
        }
    }, receiveValue: { data in
        print("Datos recibidos: \(data.count)")
    })

El tercer ejemplo muestra el uso de CurrentValueSubject para la gestión 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 y RxSwift resuelven el mismo problema — programación reactiva — pero con enfoques diferentes. Combine es un framework nativo de Apple integrado en el sistema: no requiere instalación de dependencias, está integrado con SwiftUI y Foundation. RxSwift es una biblioteca de terceros compatible con iOS 9+ y con un conjunto más amplio de operadores.

El rendimiento de Combine es superior en escenarios típicos gracias a la implementación nativa en C. RxSwift proporciona más herramientas de depuración (RxSwift.Resources.total, Debug), pero su arquitectura orientada a objetos puede ser menos eficiente en grandes flujos de datos. La elección entre ellos es un compromiso entre capacidades e integración.

Una diferencia importante es el modelo de backpressure. En Combine, el Subscriber gestiona la demand a través de Subscription, dando control explícito sobre la velocidad del flujo. En RxSwift, la backpressure no se controla por defecto — Observable emite todos los valores y Subscriber los procesa a medida que llegan. Para grandes flujos de datos, Combine es más predecible y seguro en cuanto a memoria.

Combine está profundamente integrado con SwiftUI a nivel de lenguaje. @Published genera un Publisher, ObservableObject proporciona objectWillChange Publisher. SwiftUI View se suscribe automáticamente a estos Publishers y se redibuja ante cambios. Para UIKit existen wrappers de terceros como CombineCocoa, pero Combine fue diseñado originalmente para SwiftUI, por lo que su integración en UIKit requiere código adicional. RxSwift, por otro lado, tiene un ecosistema rico para UIKit: RxCocoa proporciona wrappers reactivos para todos los elementos de UI.

Combine admite integración con Core Data a través de NSFetchedResultsController Publisher. El Publisher emite nuevos datos ante cada cambio en el stack de Core Data: agregar, eliminar, actualizar registros. Esto permite construir listas reactivas sin llamar manualmente a reloadData. Combinando Combine con NotificationCenter Publisher para UIApplication.willResignActiveNotification, los desarrolladores crean una capa reactiva para todo el ciclo de vida de la aplicación sin delegados ni callbacks. Para las clases ObservableObject, SwiftUI actualiza automáticamente la View cuando cambian las propiedades @Published — Combine maneja toda la cadena sin una sola línea de código manual. Las pruebas unitarias del código Combine se realizan mediante XCTestExpectation y Publisher.sink en casos de prueba con aislamiento de Scheduler a través de ImmediateScheduler.

Al trabajar con Combine en proyectos UIKit, los desarrolladores suelen suscribirse mediante sink y almacenar AnyCancellable en un Set. El patrón típico: ViewController crea una vista, almacena cancellables, se suscribe al Publisher de ViewModel. En deinit, todas las suscripciones se cancelan automáticamente a través de la colección Cancellables. Para el manejo correcto de UIControl en Combine, se puede usar UIControl.Event Publisher a través de la extensión publisher(for:).

La depuración de Combine se realiza mediante el operador print() o handleEvents(). print(String) registra todos los eventos: receive subscription, request demand, receive value, receive completion. handleEvents proporciona un control más preciso: se pueden especificar closures para cada etapa del ciclo de vida del Publisher. Para pruebas, existe CombineExpectations — una biblioteca que permite verificar que un Publisher emite los valores esperados en pruebas con tiempo virtual y control de demand.

Combine en la práctica

Combine se utiliza activamente en SwiftUI para la gestión de formularios: cada propiedad @Published genera un Publisher, SwiftUI se suscribe a él a través de View.body. Combinando múltiples Publishers mediante combineLatest, la validación de formularios se vuelve declarativa: cada Publisher rastrea un campo, combineLatest recopila todos los valores, map los valida y devuelve el estado del botón Submit. Publishers.Merge combina varios Publishers del mismo tipo en uno solo — útil para recopilar eventos de diferentes controles en un solo flujo.

Para la integración de Combine con UIKit, use UIControl Publisher a través de una extensión: button.publisher(for: .touchUpInside) devuelve un Publisher que emite un evento al presionar. CombineCocoa es una biblioteca de la comunidad que proporciona Publishers para todos los eventos de UIControl, UITextView.text, UIScrollView.contentOffset. Al cancelar la suscripción, el Store de cancellables se limpia en deinit, garantizando que ninguna suscripción sobreviva a su propietario. Para UIControl con múltiples estados, use Publishers.MergeMany para combinar Publishers en un array.

Preguntas frecuentes

¿Desde qué versión de iOS está disponible Combine?

Combine está disponible desde iOS 13, macOS 10.15, tvOS 13 y watchOS 6. Esto limita su uso en proyectos que requieren soporte para versiones anteriores. Para iOS 12 y versiones anteriores se utiliza RxSwift o bibliotecas de terceros.

¿En qué se diferencia PassthroughSubject de CurrentValueSubject?

PassthroughSubject no almacena estado y no repite el último valor a nuevos suscriptores — solo reciben eventos futuros. CurrentValueSubject almacena el valor actual y lo transmite inmediatamente a nuevos suscriptores. CurrentValueSubject.value permite leer y escribir el valor actual de forma síncrona.

¿Cómo se integra Combine con SwiftUI?

Combine está en el centro de SwiftUI: @Published genera un Publisher, ObservableObject utiliza objectWillChange Publisher. SwiftUI View se suscribe automáticamente a @ObservedObject y @StateObject a través del pipeline de Combine, redibujando la View cuando cambian las propiedades.

¿Qué es backpressure en Combine?

Backpressure es un mecanismo para controlar la velocidad de transferencia de datos. El Subscriber informa a Subscription cuántos valores está listo para procesar (demand). El Publisher no puede emitir más de lo solicitado. Esto es crítico al trabajar con grandes flujos de datos desde sockets de red.

¿Cómo manejar errores en Combine?

El operador catch intercepta un error y reemplaza el Publisher por uno de respaldo. replaceError reemplaza el error por un valor predeterminado. retry reintenta la suscripción un número especificado de veces ante un error. Todos los operadores deben colocarse antes de subscribe para evitar caídas en caso de Failure.

Resumen

  • Combine — un framework integrado de Apple para programación reactiva desde iOS 13
  • Publisher — un protocolo con Output y Failure, comienza a funcionar tras la suscripción
  • Subscriber — recibe valores mediante receive con soporte de gestión de demand
  • Subject (PassthroughSubject, CurrentValueSubject) — Publisher con inserción manual de eventos
  • Operadores map, filter, combineLatest, debounce, catch — la base de los pipelines
  • Backpressure mediante demand evita el desbordamiento del búfer del Subscriber
  • Elija Combine para nuevos proyectos con iOS 13+, RxSwift para soporte de versiones antiguas

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también