RxSwift este o bibliotecă de programare reactivă pentru iOS care implementează modelul Observable şi operatorii funcţionali pentru lucrul cu fluxuri asincrone de date. Portează conceptele ReactiveX (Rx) în limbajul Swift, oferind o API unică pentru gestionarea evenimentelor UI, cererilor de reţea, bazelor de date şi timerelor. Conform ReactiveX, 2025, biblioteca este utilizată în peste 60.000 de proiecte pe GitHub şi rămâne standardul de programare reactivă pentru Swift până la apariția Combine nativ. RxSwift înlocuieşte delegatele, closure-urile şi notificările cu un lanț unic de procesare a evenimentelor.
Principalele
RxSwift este portul Swift al bibliotecii ReactiveX (Rx) creată de Microsoft pentru .NET în 2012. Ideea principală Rx — să prezinte orice sursă de date asincronă ca o secvenţă Observable la care se pot aplica operatori funcţionali. În dezvoltarea iOS, RxSwift este utilizat pentru a conecta evenimentele UI (apăsări de butoane, introducere text, gesturi) cu logica aplicaţiei fără delegate explicite şi target-action.
Biblioteca constă din trei module: RxSwift (miez — Observable, Operator, Scheduler), RxCocoa (integrare cu UIKit — extensii rx pentru UIButton, UITextField, UITableView) şi RxRelay (Subject fără evenimente terminale). Această divizare permite utilizarea miezului în Swift de server şi teste, conectând UI doar pentru aplicaţiile iOS.
Conform sondajului Stack Overflow, 2025, RxSwift se află în top 5 cele mai utilizate biblioteci terțe pentru iOS. Motivul principal al popularităţii — gestionarea uniformă a tuturor modelelor asincrone: cereri de reţea prin URLSession, animaţii prin UIViewPropertyAnimator, notificări prin NotificationCenter şi delegate prin DelegateProxy — toate se reduc la Observable cu un ciclu de viaţă previzibil.
Programarea reactivă este un paradigma în care programul reacţionează la modificările datelor, nu le interoghează. În loc să scrieţi „luaţi date → procesaţi → actualizaţi UI”, programatorul descrie un lanţ de transformări: „când datele se schimbă, aplicaţi filtrul, apoi map, apoi actualizaţi UI”. RxSwift implementează acest paradigma prin lanţuri Observable cu execuţie leneşă — nimic nu se întâmplă până nu apare un abonat.
Observable — tipul fundamental RxSwift care reprezintă o secvenţă de evenimente în timp. Observable poate trimite trei tipuri de evenimente: next (valoare nouă), error (eroare, încheie fluxul) şi completed (finalizare cu succes). Există finite Observable (se încheie după trimiterea tuturor valorilor) şi infinite Observable (de ex. evenimentele UI — nu se încheie niciodată).
Ciclul de viaţă Observable include trei etape: creare (create, just, from), transformare (operatori map, filter, flatMap) şi abonare (subscribe). Fără abonare, Observable nu execută nicio acţiune — este o secvenţă leneşă. După abonare, Observable începe să trimită evenimente abonatului până când se finalizează sau abonatul anulează abonarea prin Disposable.
import RxSwift
// Crearea Observable dintr-un array
let numbers = Observable.from([1, 2, 3, 4, 5])
// Transformarea prin operatori
let squared = numbers
.filter { $0 % 2 == 0 }
.map { $0 * $0 }
// Abonarea cu gestionarea evenimentelor
let disposable = squared
.subscribe(onNext: { print($0) },
onError: { print("Error: \($0)") },
onCompleted: { print("Done") })
Subject — este un tip care este simultan Observable (se poate abona la el) şi Observer (se pot trimite evenimente în el). RxSwift oferă patru tipuri Subject: PublishSubject (doar evenimente noi), BehaviorSubject (cu valoare iniţială), ReplaySubject (tamponarea ultimelor N evenimente) şi AsyncSubject (doar ultima valoare înainte de finalizare). Subject este convenabil pentru integrarea codului imperativ (closure-uri, delegate) în lanţul reactiv.
Disposable — este un token de anulare a abonării. Când abonatul nu mai doreşte să primească evenimente, apelează disposable.dispose(). în practică se foloseşte DisposeBag: o colecţie Disposable care anulează automat toate abonările la deinizializarea proprietarului (de ex. UIViewController). Aceasta previne scurgerile de memorie inevitabile la gestionarea manuală a abonărilor.
| Tip Subject | Valoare iniţială | Repetă abonatului | Utilizare |
|---|---|---|---|
| PublishSubject | Nu | Doar evenimente noi | Evenimente UI, notificări rare |
| BehaviorSubject | Da | Ultimul + noi | Stare, flux de date |
| ReplaySubject | Nu | Tampon N + noi | Cache-izarea istoricului |
| AsyncSubject | Nu | Doar ultimul | Sarcini de calcul |
| PublishRelay | Nu | Doar noi | Fără error/completed |
Operatorii RxSwift sunt funcţii care primesc un Observable şi returnează alt Observable, transformând fluxul de date. Combinând operatori, programatorul construieşte lanţuri declarative de procesare fără variabile intermediare şi condiţii de cursă. Toţi operatorii sunt leneşi: lanţul se construieşte la descriere şi se execută la abonare.
Operatorii de transformare modifică fiecare eveniment în flux. map aplică o funcţie fiecărui element, flatMap desfăşoară Observable din fiecare element într-un flux plat, scan acumulează rezultatul intermediar (analog reduce, dar cu emisia fiecărui pas). buffer grupează elementele după timp sau cantitate, window împarte fluxul în Observable imbricate după ferestre.
// Exemplu lanț de operatori: căutare cu 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)
Operatorii de filtrare lasă să treacă doar evenimentele care îndeplinesc condiţia. filter separă după predicat, distinctUntilChanged lasă să treacă doar valorile diferite de precedenta, take şi takeWhile limitează numărul de evenimente. skip şi skipWhile sar peste primele N evenimente sau evenimentele până la îndeplinirea condiţiei. Pentru gestionarea erorilor se folosesc catchError (prindere şi înlocuire) şi retry (repetarea secvenţei la eroare).
Operatorii de combinare unesc mai multe Observable într-unul singur. combineLatest combină ultimele valori din mai multe fluxuri într-un tuplu, zip combină perechi elemente cu aceiaşi indici, merge uneşte mai multe fluxuri într-unul singur în ordinea sosirii evenimentelor. withLatestFrom combină un eveniment din fluxul principal cu ultima valoare dintr-alt flux — util pentru evenimente UI cu stare curentă.
| Categorie | Operator | Ce face |
|---|---|---|
| Transformare | map | Transformă fiecare valoare printr-o funcţie |
| Transformare | flatMap | Desfăşoară Observable imbricate în flux plat |
| Filtrare | filter | Lasă valorile după predicat |
| Filtrare | distinctUntilChanged | Lasă doar valorile modificate |
| Combinare | combineLatest | Combină ultimele valori din 2+ fluxuri |
| Combinare | zip | Combină în perechi elementele după index |
| Gestionare | debounce | Întârzie evenimentele până la pauză în flux |
| Gestionare | take | Preia primele N evenimente şi încheie fluxul |
Scheduler în RxSwift — este o abstractizare peste firul de execuţie (sau coada). Scheduler determină pe ce fir de execuţie se realizează crearea evenimentelor, transformarea şi abonarea. Spre deosebire de GCD, unde programatorul indică explicit DispatchQueue, RxSwift foloseşte doi parametri: subscribeOn (pe ce fir se execută Observable) şi observeOn (pe ce fir este apelat abonatul).
MainScheduler execută codul pe firul principal — obligatoriu pentru actualizarea UIKit (toate modificările UI trebuie să aibă loc pe main thread). SerialDispatchQueueScheduler îmbrăşează o coadă GCD secvenţială, ConcurrentDispatchQueueScheduler — una paralelă. Pentru sarcini de fundal se foloseşte ConcurrentDispatchQueueScheduler cu qos: .background sau .utility.
// Model tipic: lucru în fundal + UI pe main
apiService.fetchData()
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background))
.observeOn(MainScheduler.instance)
.subscribe(onNext: { data in
self.tableView.reloadData()
self.loadingIndicator.stopAnimating()
})
.disposed(by: disposeBag)
Utilizarea corectă a Scheduler previne blocarea UI la cereri de reţea şi calcule grele. subscribeOn influenţează întregul upstream (toţi operatorii până la observeOn se execută pe planificatorul indicat). observeOn comută downstream — toţi operatorii după observeOn se execută pe planificatorul indicat. În lanţ pot fi mai multe observeOn pentru comutarea între fire la diferite etape de transformare.
SerialDispatchQueueScheduler garantează procesarea secvenţială a evenimentelor, importantă pentru siguranţa firelor resurselor partajate. Pentru operaţii cu încărcare mare (procesare imagini, parsare JSON) utilizaţi ConcurrentDispatchQueueScheduler — RxSwift va păstra ordinea evenimentelor în cadrul unui Observable, dar Observable diferite pot fi procesate paralel.
RxSwift în proiectele iOS se aplică cel mai des pentru conectarea UI cu datele prin lanţuri reactive. RxCocoa oferă extensii rx pentru toate componentele standard UIKit: rx.tap pentru UIButton, rx.text pentru UITextField, rx.selectedRow pentru UIPickerView. Aceasta permite renunţarea la @IBAction şi delegate, înlocuindu-le cu abonări declarative.
MVVM (Model-View-ViewModel) — model arhitectural în care ViewManager gestionează starea şi logica de afaceri, iar View se abonează la proprietăţile reactive ale ViewModel. RxSwift se potriveşte perfect în MVVM: ViewModel publică Observable sau Driver pentru date, View se abonează la ele prin bind. ViewModel nu are referinţă la View — returnează Observable pe care View le consumă.
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
}
}
}
// În ViewController:
viewModel.isFormValid
.bind(to: loginButton.rx.isEnabled)
.disposed(by: disposeBag)
Cererile de reţea — al doilea domeniu ca frecvenţă de aplicare RxSwift. URLSession.rx.response îmbrăşează o cerere HTTP într-un Observable care returnează (response, data) la succes sau error la eşec. în combinaţie cu Codable şi operatorul map obţinem un strat API reactiv compact: Observable<MyModel> fără callback-uri şi gestionare a erorilor în fiecare metodă. La eroare de reţea, operatorul retry(3) repetă automat cererea de trei ori cu întârziere exponenţială.
Combine — framework nativ Apple, introdus în iOS 13. Rezolvă aceleaşi sarcini ca RxSwift: lucrul cu evenimente asincrone prin Publisher, Subscriber şi operatori. Însă Combine are diferenţe cheie: tipizare strictă a erorilor prin tipul Failure, suport încorporat pentru Swift Concurrency (async/await) şi integrare cu SwiftUI prin @Published şi ObservableObject.
RxSwift câştigă în compatibilitate inversă — suportă iOS 8+, în timp ce Combine necesită iOS 13+. RxSwift are un ecosistem mai bogat de extensii terţe (RxDataSources, RxGesture, RxAnimated) şi documentaţie detaliată a operatorilor. Pentru proiecte cu suport pentru versiuni vechi iOS, RxSwift rămâne singura alegere.
Pentru proiecte noi cu iOS 13+, Apple recomandă Combine. Este strâns integrat cu SwiftUI, are dimensiune binară mai mică şi suport oficial. Însă migrarea codului existent RxSwift la Combine necesită rescrierea tuturor Observable → Publisher, iar ecosistemul RxCocoa nu are analog complet în Combine — UIKit nu are Publisher nativi pentru toate componentele UI.
| Caracteristică | RxSwift | Combine |
|---|---|---|
| iOS minim | iOS 8+ | iOS 13+ |
| Tip eroare | Error (orice) | Generic Failure |
| Extensii UI | RxCocoa (UIKit, AppKit) | @Published (SwiftUI) |
| Operatori | 400+ operatori | ~100 operatori |
| Swift Concurrency | Prin punte | Suport nativ |
| Statut | Terţ | Apple oficial |
Întrebări frecvente
Observable — sursă de evenimente cu execuţie leneşă. Subject este simultan Observable şi Observer — vă puteţi abona la el şi trimite evenimente noi manual. Subject este util pentru integrarea codului imperativ în lanţuri reactive.
RxSwift se alege când este necesar suportul iOS 11-12, există o bază de cod RxSwift existentă sau este nevoie de un ecosistem bogat de operatori (400+ faţă de ~100 în Combine). Pentru proiecte noi pe iOS 13+ este preferabil Combine.
DisposeBag — o colecţie de tokeni Disposable care anulează automat toate abonările la deinizializarea proprietarului. Fără DisposeBag, abonarea creează o referinţă puternică la closure, ceea ce duce la scurgeri de memorie la distrugerea UIViewController.
Utilizaţi catchError pentru înlocuirea erorii cu o valoare implicită, retry pentru reexecutarea Observable, materialize pentru transformarea erorii în eveniment. în stratul UI, Driver şi Signal nu transmit erori — sunt gestionate intern.
Driver — un tip special Observable care garantează execuţia pe MainScheduler, absenţa erorilor şi partajarea resurselor. Driver garantează că actualizările UI au loc pe firul principal. Observable nu oferă astfel de garanţii — necesită observeOn.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și