RxSwift is een bibliotheek voor reactief programmeren voor iOS die het Observable-patroon en functionele operatoren implementeert voor het werken met asynchrone gegevensstromen. Het port de concepten van ReactiveX (Rx) naar Swift en biedt een uniforme API voor het verwerken van UI-gebeurtenissen, netwerkverzoeken, databases en timers. Volgens ReactiveX, 2025 wordt de bibliotheek gebruikt in meer dan 60.000 projecten op GitHub en blijft het de standaard voor reactief programmeren voor Swift tot de komst van native Combine. RxSwift vervangt delegaten, closures en meldingen door een uniforme keten voor gebeurtenisverwerking.
Belangrijkste punten
RxSwift is de Swift-port van de ReactiveX (Rx)-bibliotheek, gemaakt door Microsoft voor .NET in 2012. Het hoofdidee van Rx is om elke asynchrone gegevensbron voor te stellen als een Observable-reeks waarop functionele operatoren kunnen worden toegepast. In iOS-ontwikkeling wordt RxSwift gebruikt om UI-gebeurtenissen (knopdrukken, tekstinvoer, gebaren) te koppelen aan de applicatielogica zonder expliciete delegaten en target-action.
De bibliotheek bestaat uit drie modules: RxSwift (kern — Observable, Operator, Scheduler), RxCocoa (integratie met UIKit — rx-extensies voor UIButton, UITextField, UITableView) en RxRelay (Subject zonder terminale gebeurtenissen). Deze verdeling maakt het mogelijk om de kern te gebruiken in server-Swift en tests, terwijl de UI-koppeling alleen voor iOS-applicaties wordt aangesloten.
Volgens de Stack Overflow, 2025-enquête behoort RxSwift tot de top 5 meest gebruikte externe bibliotheken voor iOS. De belangrijkste reden voor populariteit is de uniforme verwerking van alle asynchrone patronen: netwerkverzoeken via URLSession, animaties via UIViewPropertyAnimator, meldingen via NotificationCenter en delegaten via DelegateProxy — alles wordt teruggebracht tot Observable met een voorspelbare levenscyclus.
Reactief programmeren is een paradigma waarbij het programma reageert op gegevenswijzigingen in plaats van ze te pollen. In plaats van “gegevens ophalen → verwerken → UI bijwerken” te schrijven, beschrijft de ontwikkelaar een transformatieketen: “wanneer gegevens veranderen, pas filter toe, dan map, dan werk UI bij”. RxSwift implementeert dit paradigma via Observable-ketens met luie uitvoering — er gebeurt niets totdat er een abonnee verschijnt.
Observable is het fundamentele type van RxSwift dat een reeks gebeurtenissen in de tijd vertegenwoordigt. Observable kan drie soorten gebeurtenissen verzenden: next (nieuwe waarde), error (fout, beëindigt de stroom) en completed (succesvolle voltooiing). Er bestaan finite Observable (eindigen na het verzenden van alle waarden) en infinite Observable (bijv. UI-gebeurtenissen — eindigen nooit).
Levenscyclus van Observable omvat drie fasen: creatie (create, just, from), transformatie (operatoren map, filter, flatMap) en abonneren (subscribe). Zonder abonnement voert Observable geen acties uit — het is een luie reeks. Na abonneren begint Observable gebeurtenissen naar de abonnee te sturen totdat het eindigt of de abonnee het abonnement opzegt via Disposable.
import RxSwift
// Observable maken van een array
let numbers = Observable.from([1, 2, 3, 4, 5])
// Transformatie via operatoren
let squared = numbers
.filter { $0 % 2 == 0 }
.map { $0 * $0 }
// Abonneren met gebeurtenisafhandeling
let disposable = squared
.subscribe(onNext: { print($0) },
onError: { print("Error: \($0)") },
onCompleted: { print("Done") })
Subject is een type dat tegelijkertijd Observable (men kan erop abonneren) en Observer (men kan er gebeurtenissen naartoe sturen) is. RxSwift biedt vier typen Subject: PublishSubject (alleen nieuwe gebeurtenissen), BehaviorSubject (met beginwaarde), ReplaySubject (bufferen van laatste N gebeurtenissen) en AsyncSubject (alleen laatste waarde voor voltooiing). Subject is handig voor integratie van imperatieve code (closures, delegaten) in de reactieve keten.
Disposable is een token voor het opzeggen van een abonnement. Wanneer de abonnee geen gebeurtenissen meer wil ontvangen, roept hij disposable.dispose() aan. In de praktijk wordt DisposeBag gebruikt: een verzameling Disposable die automatisch alle abonnementen opzegt bij deinitialisatie van de eigenaar (bijv. UIViewController). Dit voorkomt geheugenlekken die onvermijdelijk zijn bij handmatig beheer van abonnementen.
| Subject-type | Beginwaarde | Herhaalt aan abonnee | Gebruik |
|---|---|---|---|
| PublishSubject | Nee | Alleen nieuwe gebeurtenissen | UI-gebeurtenissen, zeldzame meldingen |
| BehaviorSubject | Ja | Laatste + nieuwe | Toestand, gegevensstroom |
| ReplaySubject | Nee | Buffer N + nieuwe | Geschiedenis cachen |
| AsyncSubject | Nee | Alleen laatste | Berekeningstaken |
| PublishRelay | Nee | Alleen nieuwe | Zonder error/completed |
Operatoren van RxSwift zijn functies die één Observable nemen en een andere Observable retourneren, waarbij de gegevensstroom wordt getransformeerd. Door operatoren te combineren, bouwt de ontwikkelaar declaratieve verwerkingsketens zonder tussenliggende variabelen en race-condities. Alle operatoren zijn lui: de keten wordt opgebouwd tijdens het beschrijven en uitgevoerd tijdens het abonneren.
Transformatie-operatoren wijzigen elke gebeurtenis in de stroom. map past een functie toe op elk element, flatMap vouwt Observable van elk element uit in één platte stroom, scan accumuleert het tussenresultaat (analoog aan reduce, maar met emissie van elke stap). buffer groepeert elementen op tijd of hoeveelheid, window verdeelt de stroom in geneste Observable per venster.
// Voorbeeld van operatorketen: zoeken met 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-operatoren laten alleen gebeurtenissen door die aan de voorwaarde voldoen. filter scheidt op predicaat, distinctUntilChanged laat alleen waarden door die verschillen van de vorige, take en takeWhile beperken het aantal gebeurtenissen. skip en skipWhile slaan de eerste N gebeurtenissen of gebeurtenissen tot aan de voorwaarde over. Voor foutafhandeling worden catchError (opvangen en vervangen) en retry (herhalen van de reeks bij fout) gebruikt.
Combinatie-operatoren voegen meerdere Observable samen tot één. combineLatest combineert de laatste waarden uit meerdere stromen in een tuple, zip combineert elementen paarsgewijs met dezelfde indices, merge voegt meerdere stromen samen in de volgorde van binnenkomst van gebeurtenissen. withLatestFrom combineert een gebeurtenis uit de hoofdstroom met de laatste waarde uit een andere stroom — handig voor UI-gebeurtenissen met huidige toestand.
| Categorie | Operator | Wat het doet |
|---|---|---|
| Transformatie | map | Transformeert elke waarde via een functie |
| Transformatie | flatMap | Vouwt geneste Observable uit in platte stroom |
| Filteren | filter | Laat waarden door op basis van predicaat |
| Filteren | distinctUntilChanged | Laat alleen gewijzigde waarden door |
| Combineren | combineLatest | Combineert laatste waarden uit 2+ stromen |
| Combineren | zip | Combineert elementen paarsgewijs op index |
| Beheer | debounce | Vertraagt gebeurtenissen tot pauze in stroom |
| Beheer | take | Neemt eerste N gebeurtenissen en beëindigt stroom |
Scheduler in RxSwift is een abstractie boven een uitvoeringsthread (of wachtrij). Scheduler bepaalt op welke thread het maken van gebeurtenissen, transformatie en abonneren plaatsvindt. In tegenstelling tot GCD, waar de ontwikkelaar expliciet DispatchQueue aangeeft, gebruikt RxSwift twee parameters: subscribeOn (op welke thread Observable wordt uitgevoerd) en observeOn (op welke thread de abonnee wordt aangeroepen).
MainScheduler voert code uit op de hoofdthread — verplicht voor het bijwerken van UIKit (alle UI-wijzigingen moeten op de main thread plaatsvinden). SerialDispatchQueueScheduler wikkelt een sequentiële GCD-wachtrij in, ConcurrentDispatchQueueScheduler een parallelle. Voor achtergrondtaken wordt ConcurrentDispatchQueueScheduler met qos: .background of .utility gebruikt.
// Typisch patroon: achtergrondwerk + UI op main
apiService.fetchData()
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background))
.observeOn(MainScheduler.instance)
.subscribe(onNext: { data in
self.tableView.reloadData()
self.loadingIndicator.stopAnimating()
})
.disposed(by: disposeBag)
Correct gebruik van Scheduler voorkomt UI-blokkering bij netwerkverzoeken en zware berekeningen. subscribeOn beïnvloedt de hele upstream (alle operatoren tot observeOn worden uitgevoerd op de aangegeven planner). observeOn schakelt downstream — alle operatoren na observeOn worden uitgevoerd op de aangegeven planner. In de keten kunnen meerdere observeOn voorkomen voor het schakelen tussen threads in verschillende transformatiefasen.
SerialDispatchQueueScheduler garandeert sequentiële verwerking van gebeurtenissen, wat belangrijk is voor threadveiligheid van gedeelde bronnen. Voor zware bewerkingen (beeldverwerking, JSON-parsing) gebruik ConcurrentDispatchQueueScheduler — RxSwift behoudt de volgorde van gebeurtenissen binnen één Observable, maar verschillende Observable kunnen parallel worden verwerkt.
RxSwift wordt in iOS-projecten het meest gebruikt voor het koppelen van UI aan gegevens via reactieve ketens. RxCocoa biedt rx-extensies voor alle standaard UIKit-componenten: rx.tap voor UIButton, rx.text voor UITextField, rx.selectedRow voor UIPickerView. Dit maakt het mogelijk om @IBAction en delegaten te vervangen door declaratieve abonnementen.
MVVM (Model-View-ViewModel) is een architectuurpatroon waarin ViewModel de toestand en bedrijfslogica beheert en View zich abonneert op de reactieve eigenschappen van ViewModel. RxSwift past perfect in MVVM: ViewModel publiceert Observable of Driver voor gegevens, View abonneert zich erop via bind. ViewModel heeft geen verwijzing naar View — het retourneert Observable die View consumeert.
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
}
}
}
// In ViewController:
viewModel.isFormValid
.bind(to: loginButton.rx.isEnabled)
.disposed(by: disposeBag)
Netwerkverzoeken zijn het tweede meest voorkomende toepassingsgebied van RxSwift. URLSession.rx.response wikkelt een HTTP-verzoek in een Observable dat (response, data) retourneert bij succes of error bij mislukking. In combinatie met Codable en de operator map krijgen we een compacte reactieve API-laag: Observable<MyModel> zonder callbacks en foutafhandeling in elke methode. Bij een netwerkfout herhaalt de operator retry(3) het verzoek automatisch drie keer met exponentiële vertraging.
Combine is een native Apple-framework, geïntroduceerd in iOS 13. Het lost dezelfde taken op als RxSwift: werken met asynchrone gebeurtenissen via Publisher, Subscriber en operatoren. Combine heeft echter belangrijke verschillen: strikte typering van fouten via het Failure-type, ingebouwde ondersteuning voor Swift Concurrency (async/await) en integratie met SwiftUI via @Published en ObservableObject.
RxSwift wint in achterwaartse compatibiliteit — het ondersteunt iOS 8+, terwijl Combine iOS 13+ vereist. RxSwift heeft een rijker ecosysteem van externe extensies (RxDataSources, RxGesture, RxAnimated) en gedetailleerde documentatie van operatoren. Voor projecten die oudere iOS-versies ondersteunen, blijft RxSwift de enige keuze.
Voor nieuwe projecten met iOS 13+ beveelt Apple Combine aan. Het is nauw geïntegreerd met SwiftUI, heeft een kleinere binaire grootte en officiële ondersteuning. Het migreren van bestaande RxSwift-code naar Combine vereist echter het herschrijven van alle Observable → Publisher, en het RxCocoa-ecosysteem heeft geen volledig equivalent in Combine — UIKit heeft geen native Publisher voor alle UI-componenten.
| Kenmerk | RxSwift | Combine |
|---|---|---|
| Minimale iOS | iOS 8+ | iOS 13+ |
| Fouttype | Error (willekeurig) | Generic Failure |
| UI-extensies | RxCocoa (UIKit, AppKit) | @Published (SwiftUI) |
| Operatoren | 400+ operatoren | ~100 operatoren |
| Swift Concurrency | Via brug | Native ondersteuning |
| Status | Extern | Officieel Apple |
Veelgestelde vragen
Observable is een gebeurtenisbron met luie uitvoering. Subject is tegelijkertijd Observable en Observer — u kunt erop abonneren en er handmatig nieuwe gebeurtenissen naartoe sturen. Subject is handig voor integratie van imperatieve code in reactieve ketens.
RxSwift wordt gekozen bij ondersteuning van iOS 11-12, bij een bestaande RxSwift-codebasis of bij behoefte aan een rijk operatoren-ecosysteem (400+ versus ~100 in Combine). Voor nieuwe projecten op iOS 13+ heeft Combine de voorkeur.
DisposeBag is een verzameling Disposable-tokens die automatisch alle abonnementen opzegt bij deinitialisatie van de eigenaar. Zonder DisposeBag maakt een abonnement een sterke verwijzing naar de closure, wat leidt tot geheugenlekken bij vernietiging van UIViewController.
Gebruik catchError om een fout te vervangen door een standaardwaarde, retry voor heruitvoering van Observable, materialize om een fout om te zetten in een gebeurtenis. In de UI-laag geven Driver en Signal geen fouten door — ze worden intern afgehandeld.
Driver is een speciaal type Observable dat uitvoering op MainScheduler, afwezigheid van fouten en delen van bronnen garandeert. Driver garandeert dat UI-updates op de hoofdthread plaatsvinden. Observable geeft dergelijke garanties niet — observeOn is vereist.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook