RxSwift — это библиотека реактивного программирования для iOS, реализующая паттерн Observable и функциональные операторы для работы с асинхронными потоками данных. Она портирует концепции ReactiveX (Rx) на язык Swift, предоставляя единый API для обработки событий от UI, сетевых запросов, БД и таймеров. По данным ReactiveX, 2025, библиотека используется более чем в 60 000 проектах на GitHub и остаётся стандартом реактивного программирования для Swift до появления нативного Combine. RxSwift заменяет делегаты, замыкания и уведомления единой цепочкой обработки событий.
Главно
RxSwift — это Swift-порт библиотеки ReactiveX (Rx), созданной компанией Microsoft для .NET в 2012 году. Основная идея Rx — представить любой асинхронный источник данных как Observable последовательность, к которой можно применять функциональные операторы. В iOS-разработке RxSwift используется для связывания UI-событий (нажатия кнопок, ввод текста, жесты) с логикой приложения без явных делегатов и target-action.
Библиотека состоит из трёх модулей: RxSwift (ядро — Observable, Operator, Scheduler), RxCocoa (интеграция с UIKit — rx-расширения для UIButton, UITextField, UITableView) и RxRelay (Subject без терминальных событий). Такое разделение позволяет использовать ядро в серверном Swift и тестах, подключая UI-обвязку только для iOS-приложений.
Согласно опросу Stack Overflow, 2025, RxSwift входит в топ-5 наиболее используемых сторонних библиотек для iOS. Основная причина популярности — единообразная обработка всех асинхронных паттернов: сетевые запросы через URLSession, анимации через UIViewPropertyAnimator, уведомления через NotificationCenter и делегаты через DelegateProxy — всё это сводится к Observable с предсказуемым жизненным циклом.
Реактивное программирование — это парадигма, в которой программа реагирует на изменения данных, а не опрашивает их. Вместо того чтобы писать «получить данные → обработать → обновить UI», разработчик описывает цепочку трансформаций: «когда данные изменятся, применить фильтр, затем map, затем обновить UI». RxSwift реализует эту парадигму через Observable цепочки с ленивым выполнением — ничего не происходит, пока не появится подписчик.
Observable — фундаментальный тип RxSwift, представляющий последовательность событий во времени. Observable может отправлять три типа событий: next (новое значение), error (ошибка, завершающая поток) и completed (успешное завершение). Существуют finite Observable (завершаются после отправки всех значений) и infinite Observable (например, UI-события — никогда не завершаются).
Жизненный цикл Observable включает три стадии: создание (create, just, from), трансформация (операторы map, filter, flatMap) и подписка (subscribe). Без подписки Observable не выполняет никаких действий — это ленивая последовательность. После подписки Observable начинает отправлять события подписчику до тех пор, пока не завершится или подписчик не отменит подписку через Disposable.
import RxSwift
// Креирање Observable-а из низа
let numbers = Observable.from([1, 2, 3, 4, 5])
// Трансформација кроз операторе
let squared = numbers
.filter { $0 % 2 == 0 }
.map { $0 * $0 }
// Претплата са обрадом догађаја
let disposable = squared
.subscribe(onNext: { print($0) },
onError: { print("Error: \($0)") },
onCompleted: { print("Done") })
Subject — это тип, который одновременно является Observable (на него можно подписаться) и Observer (в него можно отправлять события). RxSwift предоставляет четыре типа Subject: PublishSubject (только новые события), BehaviorSubject (с начальным значением), ReplaySubject (буферизация последних N событий) и AsyncSubject (только последнее значение перед завершением). Subject удобен для интеграции императивного кода (замыкания, делегаты) в реактивную цепочку.
Disposable — это токен отмены подписки. Когда подписчик больше не хочет получать события, он вызывает disposable.dispose(). На практике используется DisposeBag: коллекция Disposable, которая автоматически отменяет все подписки при деинициализации владельца (например, UIViewController). Это предотвращает утечки памяти, неизбежные при ручном управлении подписками.
| Тип Subject | Начальное значение | Повторяет подписчику | Использование |
|---|---|---|---|
| PublishSubject | Нет | Только новые события | UI-события, редкие уведомления |
| BehaviorSubject | Да | Последнее + новые | Состояние, стрим данных |
| ReplaySubject | Нет | Буфер N + новые | Кэширование истории |
| AsyncSubject | Нет | Только последнее | Вычислительные задачи |
| PublishRelay | Нет | Только новые | Без error/completed |
Операторы RxSwift — это функции, которые принимают один Observable и возвращают другой Observable, трансформируя поток данных. Комбинируя операторы, разработчик строит декларативные цепочки обработки без промежуточных переменных и состояний гонок. Все операторы ленивы: цепочка строится при описании, а выполняется при подписке.
Операторы трансформации изменяют каждое событие в потоке. map применяет функцию к каждому элементу, flatMap разворачивает Observable от каждого элемента в один плоский поток, scan накапливает промежуточный результат (аналог reduce, но с эмиссией каждого шага). buffer группирует элементы по времени или количеству, window делит поток на вложенные Observable по окнам.
// Пример ланца оператора: претрага са 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)
Операторы фильтрации пропускают только те события, которые удовлетворяют условию. filter отсеивает по предикату, distinctUntilChanged пропускает только значения, отличные от предыдущего, take и takeWhile ограничивают количество событий. skip и skipWhile пропускают первые N событий или события до выполнения условия. Для обработки ошибок используются catchError (перехват и подмена) и retry (повтор последовательности при ошибке).
Операторы комбинирования объединяют несколько Observable в один. combineLatest объединяет последние значения из нескольких потоков в кортеж, zip попарно комбинирует элементы с одинаковыми индексами, merge объединяет несколько потоков в один в порядке поступления событий. withLatestFrom комбинирует событие из основного потока с последним значением из другого потока — удобно для UI-событий с текущим состоянием.
| Категория | Оператор | Что делает |
|---|---|---|
| Трансформация | map | Преобразует каждое значение через функцию |
| Трансформация | flatMap | Разворачивает вложенные Observable в плоский поток |
| Фильтрация | filter | Пропускает значения по предикату |
| Фильтрация | distinctUntilChanged | Пропускает только изменившиеся значения |
| Комбинирование | combineLatest | Объединяет последние значения из 2+ потоков |
| Комбинирование | zip | Попарно комбинирует элементы по индексу |
| Управление | debounce | Задерживает события до паузы в потоке |
| Управление | take | Берёт первые N событий и завершает поток |
Scheduler в RxSwift — это абстракция над потоком выполнения (или очередью). Scheduler определяет, на каком потоке выполняется создание событий, трансформация и подписка. В отличие от GCD, где разработчик явно указывает DispatchQueue, RxSwift использует два параметра: subscribeOn (на каком потоке выполняется Observable) и observeOn (на каком потоке вызывается подписчик).
MainScheduler выполняет код на главном потоке — обязателен для обновления UIKit (все UI-изменения должны происходить на main thread). SerialDispatchQueueScheduler оборачивает последовательную GCD-очередь, ConcurrentDispatchQueueScheduler — параллельную. Для фоновых задач используется ConcurrentDispatchQueueScheduler с qos: .background или .utility.
// Типичан образац: посадински рад + UI на main
apiService.fetchData()
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background))
.observeOn(MainScheduler.instance)
.subscribe(onNext: { data in
self.tableView.reloadData()
self.loadingIndicator.stopAnimating()
})
.disposed(by: disposeBag)
Правильное использование Scheduler предотвращает блокировку UI при сетевых запросах и тяжёлых вычислениях. subscribeOn влияет на весь upstream (все операторы до observeOn выполняются на указанном планировщике). observeOn переключает downstream — все операторы после observeOn выполняются на указанном планировщике. В цепочке может быть несколько observeOn для переключения между потоками на разных этапах трансформации.
SerialDispatchQueueScheduler гарантирует последовательную обработку событий, что важно для потокобезопасности общих ресурсов. Для высоконагруженных операций (обработка изображений, парсинг JSON) используйте ConcurrentDispatchQueueScheduler — RxSwift сохранит порядок событий внутри одного Observable, но разные Observable могут обрабатываться параллельно.
RxSwift в iOS-проектах чаще всего применяется для связывания UI с данными через реактивные цепочки. RxCocoa предоставляет rx-расширения для всех стандартных UIKit-компонентов: rx.tap для UIButton, rx.text для UITextField, rx.selectedRow для UIPickerView. Это позволяет отказаться от @IBAction и делегатов, заменив их декларативными подписками.
MVVM (Model-View-ViewModel) — архитектурный паттерн, в котором ViewModel управляет состоянием и бизнес-логикой, а View подписывается на реактивные свойства ViewModel. RxSwift идеально вписывается в MVVM: ViewModel публикует Observable или Driver для данных, View подписывается на них через bind. ViewModel не имеет ссылки на View — она возвращает Observable, которые View потребляет.
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
}
}
}
// У ViewController-у:
viewModel.isFormValid
.bind(to: loginButton.rx.isEnabled)
.disposed(by: disposeBag)
Сетевые запросы — вторая по частоте область применения RxSwift. URLSession.rx.response оборачивает HTTP-запрос в Observable, который возвращает (response, data) при успехе или error при неудаче. В комбинации с Codable и оператором map получается компактный реактивный слой API: Observable
Combine — нативный фреймворк Apple, представленный в iOS 13. Он решает те же задачи, что и RxSwift: работа с асинхронными событиями через Publisher, Subscriber и операторы. Однако Combine имеет ключевые отличия: строгая типизация ошибок через Failure тип, встроенная поддержка Swift Concurrency (async/await) и интеграция с SwiftUI через @Published и ObservableObject.
RxSwift выигрывает в обратной совместимости — он поддерживает iOS 8+, тогда как Combine требует iOS 13+. RxSwift имеет более богатую экосистему сторонних расширений (RxDataSources, RxGesture, RxAnimated) и детальную документацию по операторам. Для проектов с поддержкой старых версий iOS RxSwift остаётся единственным выбором.
Для новых проектов с iOS 13+ Apple рекомендует Combine. Он тесно интегрирован с SwiftUI, имеет меньший размер бинарника и официальную поддержку. Однако миграция существующего RxSwift-кода на Combine требует переписывания всех Observable → Publisher, а экосистема RxCocoa не имеет полного Combine-аналога — UIKit не имеет нативных [Publisher] для всех UI-компонентов.
| Характеристика | RxSwift | Combine |
|---|---|---|
| Минимальная iOS | iOS 8+ | iOS 13+ |
| Тип ошибки | Error (любая) | Generic Failure |
| UI-расширения | RxCocoa (UIKit, AppKit) | @Published (SwiftUI) |
| Операторы | 400+ операторов | ~100 операторов |
| Swift Concurrency | Через бридж | Нативная поддержка |
| Статус | Сторонняя | Apple официально |
Често постављана питања
Observable — источник событий с ленивым выполнением. Subject одновременно является Observable и Observer — вы можете подписаться на него и отправлять в него новые события вручную. Subject удобен для интеграции императивного кода в реактивные цепочки.
RxSwift выбирают при необходимости поддержки iOS 11-12, при наличии существующей RxSwift-кодовой базы или при потребности в богатой экосистеме операторов (400+ против ~100 в Combine). Для новых проектов на iOS 13+ предпочтителен Combine.
DisposeBag — коллекция токенов Disposable, автоматически отменяющая все подписки при деинициализации владельца. Без DisposeBag подписка создаёт strong reference на замыкание, что приводит к утечке памяти при уничтожении UIViewController.
Используйте catchError для замены ошибки значением по умолчанию, retry для повторного выполнения Observable, materialize для преобразования ошибки в событие. В UI-слое Driver и Signal не передают ошибки — они обрабатываются внутри.
Driver — это специальный тип Observable, гарантирующий выполнение на MainScheduler, отсутствие ошибок и sharing ресурсов. Driver гарантирует, что UI-обновления происходят на главном потоке. Observable не даёт таких гарантий — требуется observeOn.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође