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 за преключване между нишки на различни етапи на трансформацията.
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<MyModel> без callback-и и обработка на грешки в всяка метода. При мрежова грешка операторът retry(3) автоматично повтаря заявката три пъти с експоненциално забавяне.
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, абонаментът създава силна референция към затварянето, което води до изтичане на памет при унищожаването на UIViewController.
Използвайте catchError за замяна на грешката с стойност по подразбиране, retry за повторно изпълнение на Observable, materialize за превръщане на грешката в събитие. В UI слоя Driver и Signal не предават грешки — те се обработват внутрешно.
Driver е специален тип Observable, който гарантира изпълнение на MainScheduler, липса на грешки и споделяне на ресурси. Driver гарантира, че UI актуализациите се случват на основната нишка. Observable не предоставя такива гаранции — изисква се observeOn.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също