RxSwift es una librería de programación reactiva para iOS que implementa el patrón Observable y operadores funcionales para trabajar con flujos de datos asíncronos. Porta los conceptos de ReactiveX (Rx) a Swift, proporcionando una API unificada para manejar eventos de UI, peticiones de red, bases de datos y temporizadores. Según ReactiveX, 2025, la librería se utiliza en más de 60 000 proyectos en GitHub y sigue siendo el estándar de programación reactiva para Swift hasta la llegada de Combine nativo. RxSwift reemplaza delegados, closures y notificaciones con una única cadena de procesamiento de eventos.
Puntos clave
RxSwift es el puerto Swift de la librería ReactiveX (Rx) creada por Microsoft para .NET en 2012. La idea central de Rx es representar cualquier fuente de datos asíncrona como una secuencia Observable a la que se pueden aplicar operadores funcionales. En el desarrollo iOS, RxSwift se utiliza para vincular eventos de UI (toques de botones, entrada de texto, gestos) con la lógica de la aplicación sin delegados explícitos ni target-action.
La librería consta de tres módulos: RxSwift (núcleo — Observable, Operator, Scheduler), RxCocoa (integración con UIKit — extensiones rx para UIButton, UITextField, UITableView) y RxRelay (Subject sin eventos terminales). Esta separación permite usar el núcleo en Swift del lado del servidor y en pruebas, conectando el envoltorio UI solo para aplicaciones iOS.
Según la encuesta Stack Overflow, 2025, RxSwift se encuentra entre las 5 librerías de terceros más utilizadas para iOS. La razón principal de su popularidad es el manejo uniforme de todos los patrones asíncronos: peticiones de red mediante URLSession, animaciones mediante UIViewPropertyAnimator, notificaciones mediante NotificationCenter y delegados mediante DelegateProxy — todo se reduce a un Observable con un ciclo de vida predecible.
La programación reactiva es un paradigma en el que el programa reacciona a los cambios de datos en lugar de consultarlos periódicamente. En lugar de escribir “obtener datos → procesar → actualizar UI”, el desarrollador describe una cadena de transformaciones: “cuando los datos cambien, aplicar filtro, luego map, luego actualizar UI”. RxSwift implementa este paradigma a través de cadenas Observable con ejecución perezosa — no ocurre nada hasta que aparece un suscriptor.
Observable es el tipo fundamental de RxSwift que representa una secuencia de eventos en el tiempo. Observable puede enviar tres tipos de eventos: next (nuevo valor), error (error que termina el flujo) y completed (finalización exitosa). Existen Observable finitos (se completan después de enviar todos los valores) y Observable infinitos (por ejemplo, eventos de UI — nunca se completan).
El ciclo de vida de un Observable incluye tres etapas: creación (create, just, from), transformación (operadores map, filter, flatMap) y suscripción (subscribe). Sin una suscripción, Observable no realiza ninguna acción — es una secuencia perezosa. Después de la suscripción, Observable comienza a enviar eventos al suscriptor hasta que se completa o el suscriptor cancela la suscripción mediante Disposable.
import RxSwift
// Crear Observable desde un array
let numbers = Observable.from([1, 2, 3, 4, 5])
// Transformación mediante operadores
let squared = numbers
.filter { $0 % 2 == 0 }
.map { $0 * $0 }
// Suscripción con manejo de eventos
let disposable = squared
.subscribe(onNext: { print($0) },
onError: { print("Error: \($0)") },
onCompleted: { print("Done") })
Subject es un tipo que es tanto un Observable (se puede suscribir) como un Observer (puede enviar eventos). RxSwift proporciona cuatro tipos de Subject: PublishSubject (solo eventos nuevos), BehaviorSubject (con un valor inicial), ReplaySubject (almacena en búfer los últimos N eventos) y AsyncSubject (solo el último valor antes de completarse). Subject es útil para integrar código imperativo (closures, delegados) en una cadena reactiva.
Disposable es un token de cancelación de suscripción. Cuando el suscriptor ya no desea recibir eventos, llama a disposable.dispose(). En la práctica, se usa DisposeBag: una colección de Disposable que cancela automáticamente todas las suscripciones al desinicializar el propietario (por ejemplo, UIViewController). Esto evita fugas de memoria inevitables con la gestión manual de suscripciones.
| Tipo de Subject | Valor inicial | Reenvía al suscriptor | Caso de uso |
|---|---|---|---|
| PublishSubject | No | Solo eventos nuevos | Eventos de UI, notificaciones poco frecuentes |
| BehaviorSubject | Sí | Último + nuevos | Estado, flujo de datos |
| ReplaySubject | No | Búfer N + nuevos | Almacenamiento en caché de historial |
| AsyncSubject | No | Solo el último | Tareas computacionales |
| PublishRelay | No | Solo nuevos | Sin error/completed |
Los operadores en RxSwift son funciones que toman un Observable y devuelven otro Observable, transformando el flujo de datos. Combinando operadores, el desarrollador construye cadenas de procesamiento declarativas sin variables intermedias ni condiciones de carrera. Todos los operadores son perezosos: la cadena se construye al describirla y se ejecuta al suscribirse.
Los operadores de transformación cambian cada evento en el flujo. map aplica una función a cada elemento, flatMap despliega Observable de cada elemento en un único flujo plano, scan acumula resultados intermedios (similar a reduce pero emitiendo cada paso). buffer agrupa elementos por tiempo o cantidad, window divide el flujo en Observable anidados por ventanas.
// Ejemplo de cadena de operadores: búsqueda con debounce
searchTextField.rx.text
.orEmpty
.debounce(.milliseconds(300), scheduler: MainScheduler.instance)
.distinctUntilChanged()
.flatMapLatest { query -> Observable<[String]> in
return apiService.search(query)
}
.bind(to: tableView.rx.items(cellIdentifier: "Cell")) { _, item, cell in
cell.textLabel?.text = item
}
.disposed(by: disposeBag)
Los operadores de filtrado solo dejan pasar eventos que cumplen una condición. filter filtra por predicado, distinctUntilChanged solo pasa valores diferentes del anterior, take y takeWhile limitan el número de eventos. skip y skipWhile saltan los primeros N eventos o eventos hasta que se cumpla una condición. Para el manejo de errores se utilizan catchError (interceptar y sustituir) y retry (reintentar la secuencia en caso de error).
Los operadores de combinación combinan múltiples Observables en uno. combineLatest fusiona los últimos valores de varios flujos en una tupla, zip empareja elementos con los mismos índices, merge combina varios flujos en uno en el orden de llegada de los eventos. withLatestFrom combina un evento del flujo principal con el último valor de otro flujo — útil para eventos de UI con estado actual.
| Categoría | Operador | Qué hace |
|---|---|---|
| Transformación | map | Transforma cada valor mediante una función |
| Transformación | flatMap | Despliega Observables anidados en un flujo plano |
| Filtrado | filter | Deja pasar valores según un predicado |
| Filtrado | distinctUntilChanged | Deja pasar solo valores cambiados |
| Combinación | combineLatest | Combina los últimos valores de 2+ flujos |
| Combinación | zip | Empareja elementos por índice |
| Control | debounce | Retrasa eventos hasta una pausa en el flujo |
| Control | take | Toma los primeros N eventos y completa el flujo |
Scheduler en RxSwift es una abstracción sobre el hilo de ejecución (o cola). Scheduler determina en qué hilo se ejecutan la creación de eventos, la transformación y la suscripción. A diferencia de GCD, donde el desarrollador especifica explícitamente DispatchQueue, RxSwift utiliza dos parámetros: subscribeOn (en qué hilo se ejecuta el Observable) y observeOn (en qué hilo se llama al suscriptor).
MainScheduler ejecuta código en el hilo principal — obligatorio para actualizar UIKit (todos los cambios de UI deben ocurrir en el hilo principal). SerialDispatchQueueScheduler envuelve una cola GCD serial, ConcurrentDispatchQueueScheduler una concurrente. Para tareas en segundo plano se usa ConcurrentDispatchQueueScheduler con qos: .background o .utility.
// Patrón típico: trabajo en segundo plano + UI en main
apiService.fetchData()
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background))
.observeOn(MainScheduler.instance)
.subscribe(onNext: { data in
self.tableView.reloadData()
self.loadingIndicator.stopAnimating()
})
.disposed(by: disposeBag)
El uso correcto de Scheduler evita el bloqueo de la UI durante peticiones de red y cálculos pesados. subscribeOn afecta a todo el upstream (todos los operadores antes de observeOn se ejecutan en el planificador especificado). observeOn cambia el downstream — todos los operadores después de observeOn se ejecutan en el planificador especificado. Una cadena puede tener varios observeOn para cambiar entre hilos en diferentes etapas de transformación.
SerialDispatchQueueScheduler garantiza el procesamiento secuencial de eventos, lo que es importante para la seguridad de hilos de recursos compartidos. Para operaciones de alta carga (procesamiento de imágenes, análisis JSON) use ConcurrentDispatchQueueScheduler — RxSwift preservará el orden de los eventos dentro de un Observable, pero diferentes Observables pueden procesarse en paralelo.
RxSwift en proyectos iOS se utiliza más a menudo para vincular la UI con los datos a través de cadenas reactivas. RxCocoa proporciona extensiones rx para todos los componentes estándar de UIKit: rx.tap para UIButton, rx.text para UITextField, rx.selectedRow para UIPickerView. Esto permite abandonar @IBAction y delegados, reemplazándolos con suscripciones declarativas.
MVVM (Model-View-ViewModel) es un patrón arquitectónico en el que ViewModel gestiona el estado y la lógica de negocio, y View se suscribe a las propiedades reactivas de ViewModel. RxSwift encaja perfectamente con MVVM: ViewModel publica Observable o Driver para los datos, View se suscribe a ellos mediante bind. ViewModel no tiene referencia a View — devuelve Observable que View consume.
class LoginViewModel {
let email = BehaviorRelay<String>(value: "")
let password = BehaviorRelay<String>(value: "")
var isFormValid: Observable<Bool> {
return Observable
.combineLatest(email, password) {
!$0.isEmpty && $0.contains("@") && $1.count >= 6
}
}
}
// En ViewController:
viewModel.isFormValid
.bind(to: loginButton.rx.isEnabled)
.disposed(by: disposeBag)
Las peticiones de red son el segundo caso de uso más común de RxSwift. URLSession.rx.response envuelve una petición HTTP en un Observable que devuelve (response, data) en caso de éxito o error en caso de fallo. En combinación con Codable y el operador map, se obtiene una capa API reactiva compacta: Observable<MyModel> sin callbacks ni manejo de errores en cada método. Ante un error de red, el operador retry(3) reintenta automáticamente la petición tres veces con retroceso exponencial.
Combine es el framework nativo de Apple presentado en iOS 13. Resuelve las mismas tareas que RxSwift: trabajar con eventos asíncronos mediante Publisher, Subscriber y operadores. Sin embargo, Combine tiene diferencias clave: tipado estricto de errores mediante el tipo Failure, soporte integrado de Swift Concurrency (async/await) e integración con SwiftUI a través de @Published y ObservableObject.
RxSwift gana en compatibilidad hacia atrás — soporta iOS 8+, mientras que Combine requiere iOS 13+. RxSwift tiene un ecosistema más rico de extensiones de terceros (RxDataSources, RxGesture, RxAnimated) y documentación detallada de operadores. Para proyectos que soportan versiones antiguas de iOS, RxSwift sigue siendo la única opción.
Para proyectos nuevos con iOS 13+, Apple recomienda Combine. Está estrechamente integrado con SwiftUI, tiene un tamaño binario más pequeño y soporte oficial. Sin embargo, migrar código RxSwift existente a Combine requiere reescribir todos los Observable → Publisher, y el ecosistema de RxCocoa no tiene un equivalente completo en Combine — UIKit no tiene Publisher nativo para todos los componentes de UI.
| Característica | RxSwift | Combine |
|---|---|---|
| iOS mínimo | iOS 8+ | iOS 13+ |
| Tipo de error | Error (cualquiera) | Generic Failure |
| Extensiones UI | RxCocoa (UIKit, AppKit) | @Published (SwiftUI) |
| Operadores | 400+ operadores | ~100 operadores |
| Swift Concurrency | Mediante bridge | Soporte nativo |
| Estado | De terceros | Apple oficial |
Preguntas frecuentes
Observable es una fuente de eventos con ejecución perezosa. Subject es tanto un Observable como un Observer — puedes suscribirte a él y enviarle nuevos eventos manualmente. Subject es útil para integrar código imperativo en cadenas reactivas.
RxSwift se elige cuando se necesita soporte para iOS 11-12, cuando existe una base de código RxSwift existente o cuando se requiere un ecosistema rico de operadores (400+ frente a ~100 en Combine). Para proyectos nuevos en iOS 13+ se prefiere Combine.
DisposeBag es una colección de tokens Disposable que cancela automáticamente todas las suscripciones al desinicializar el propietario. Sin DisposeBag, la suscripción crea una referencia fuerte al closure, lo que provoca fugas de memoria al destruir UIViewController.
Use catchError para reemplazar un error con un valor por defecto, retry para reintentar la ejecución del Observable, materialize para transformar el error en un evento. En la capa de UI, Driver y Signal no transmiten errores — se manejan internamente.
Driver es un tipo especial de Observable que garantiza la ejecución en MainScheduler, ausencia de errores y uso compartido de recursos. Driver asegura que las actualizaciones de UI ocurren en el hilo principal. Observable no ofrece tales garantías — se requiere observeOn.
Resumen
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.
Lea también