RxSwift to biblioteka programowania reaktywnego dla Swift, implementująca wzorzec Observable. Według danych ReactiveX, 2025, jest to najpopularniejsza implementacja Reactive Extensions dla ekosystemu Apple. Observable jest źródłem zdarzeń, a Observer subskrybuje je.
Najważniejsze
RxSwift to biblioteka programowania reaktywnego dla języka Swift, przeniesiona z Reactive Extensions (Rx). Pozwala opisywać programy asynchroniczne i sterowane zdarzeniami poprzez Observable Sequence — sekwencję danych dostępnych w czasie. Deweloperzy iOS używają RxSwift do obsługi zapytań sieciowych, zdarzeń UI i danych strumieniowych bez zagnieżdżonych callback.
Podstawę RxSwift stanowią dwa kluczowe protokoły: ObservableType — źródło zdarzeń, które może emitować trzy typy sygnałów: .next(value), .error(error) i .completed. Observer subskrybuje Observable za pomocą metody subscribe i otrzymuje te zdarzenia. Taki model nazywa się Reactive Streams i gwarantuje, że żadne zdarzenie nie zostanie utracone przy prawidłowej subskrypcji.
RxSwift udostępnia ponad 300 operatorów do pracy ze strumieniami: map przekształca każde zdarzenie, filter przepuszcza tylko pasujące, flatMap rozwija zagnieżdżone Observable w jeden strumień. Operatory łączy się w łańcuchy, tworząc deklaratywny pipeline przetwarzania danych bez efektów ubocznych.
Oprócz podstawowego Observable, RxSwift udostępnia wyspecjalizowane typy opakowujące. Single emituje dokładnie jedną wartość lub błąd — idealny do zapytań HTTP. Completable kończy się sukcesem lub błędem bez wartości — dla operacji zapisu. Maybe łączy oba scenariusze: może zakończyć się z wartością, bez wartości lub z błędem. Te Traits upraszczają semantykę i czynią kod samodokumentującym.
Programowanie reaktywne w RxSwift opiera się na wzorcu Observer. ObservableSequence to odpowiednik Sequence z biblioteki standardowej, ale z asynchronicznym dostępem do elementów. Strumień zdarzeń przekazywany jest przez łańcuch operatorów, z których każdy zwraca nową ObservableSequence, nie mutując oryginalnej.
Operatory w RxSwift to czyste funkcje, przyjmujące jedną ObservableSequence i zwracające nową. Na przykład map tworzy nową sekwencję, stosując transformację do każdego elementu. Łącząc operatory, deweloper buduje pipeline, w którym dane przechodzą przez wszystkie etapy przetwarzania bez zmiennych pośrednich.
Schedulers to abstrakcja nad wątkami wykonania w RxSwift. Scheduler określa, na którym wątku będzie wykonywany kod: MainScheduler — wątek UI, SerialDispatchQueueScheduler — kolejka tła. Operatory subscribeOn i observeOn określają, gdzie wykonywana jest praca i gdzie przetwarzane są wyniki.
RxSwift zawiera kilka podstawowych typów, z których każdy rozwiązuje swoje zadanie w reaktywnym pipeline. Single — Observable emitujący dokładnie jedną wartość lub błąd, wygodny do zapytań sieciowych. Completable kończy się sukcesem lub błędem bez wartości. Maybe łączy właściwości Single i Completable.
Subject to gorący Observable, który jednocześnie pełni rolę Observera. PublishSubject emituje tylko nowe zdarzenia subskrybentom, BehaviorSubject — ostatnie zdarzenie plus nowe. Relay to wariant Subject, który nie emituje .error ani .completed, gwarantując ciągłość strumienia. BehaviorRelay przechowuje bieżącą wartość i nadaje się do State-driven UI.
DisposeBag to kolekcja Disposable, automatycznie anulująca wszystkie subskrypcje przy swojej dealokacji. W iOS DisposeBag jest zwykle dodawany do UIViewController lub UIView. Przy zamknięciu ekranu DisposeBag jest czyszczony — zapobiega to wyciekom pamięci i odwołaniom do nieistniejących elementów UI.
Poniżej pokazano przykład tworzenia Observable z tablicy danych z użyciem operatora map do przekształcania ciągów znaków:
let observable = Observable.of("Swift", "RxSwift", "Reactive")
observable
.map { $0.uppercased() }
.subscribe(onNext: { value in
print("Otrzymano: \(value)")
})
.disposed(by: disposeBag)
W drugim przykładzie pokazano łączenie dwóch zapytań sieciowych za pomocą zip — operator czeka, aż oba Observable wyemitują wartość, i łączy wyniki w krotkę:
let first = fetchUser(id: "123")
let second = fetchPosts(userId: "123")
Observable
.zip(first, second)
.observe(on: MainScheduler.instance)
.subscribe(onNext: { user, posts in
updateUI(user: user, posts: posts)
})
.disposed(by: disposeBag)
Trzeci przykład pokazuje użycie BehaviorRelay do przechowywania stanu i automatycznej aktualizacji UI przy zmianach: każda zmiana state.accept() jest natychmiast transmitowana subskrybentom, co idealnie nadaje się do wzorców State w architekturze MVVM.
let state = BehaviorRelay(value: "idle")
state
.subscribe(onNext: { status in
print("Status: \(status)")
})
.disposed(by: disposeBag)
state.accept("loading") // Wypisze: Status: loading
RxSwift różni się od tradycyjnych metod asynchroniczności (Delegation, NotificationCenter, Callback) deklaratywnością i komponowalnością. W przeciwieństwie do Combine, RxSwift obsługuje iOS 9+ i ma więcej operatorów. Jednak Combine jest zintegrowany z Foundation i SwiftUI na poziomie języka, co daje mu przewagę w nowych projektach Apple.
Główna zaleta RxSwift nad GCD (Grand Central Dispatch) — możliwość łączenia i przekształcania strumieni danych na poziomie abstrakcji, a nie ręcznego zarządzania kolejkami. Jednocześnie RxSwift wymaga nauki koncepcji podejścia reaktywnego, co podnosi próg wejścia dla zespołu.
W praktyce RxSwift jest używany w dużych projektach, gdzie reaktywne łańcuchy łączą zdarzenia UI, logikę biznesową i komunikację sieciową w jeden pipeline. Na przykład w aplikacjach tradingowych strumienie notowań są przetwarzane przez RxSwift: ticki przychodzą z WebSocket, przechodzą filtrację, grupowanie według ram czasowych i wyświetlanie na wykresie w czasie rzeczywistym. Taki scenariusz jest trudny do zrealizowania przez Delegation lub NotificationCenter bez utraty czytelności.
Alternatywy dla RxSwift obejmują Combine (iOS 13+), AsyncSequence z Swift Concurrency (iOS 15+), a także biblioteki zewnętrzne ReactiveSwift bez powiązania z platformami Apple. Wybór zależy od minimalnej obsługiwanej wersji iOS i doświadczenia deweloperów. W nowych projektach iOS 15+ zespoły często wybierają AsyncSequence — nie wymaga instalacji bibliotek i używa natywnych konstrukcji języka Swift.
Wzorce architektoniczne z RxSwift zwykle podążają za MVVM lub Clean Architecture. ViewModel zawiera całą logikę biznesową w postaci łańcuchów Observable, View subskrybuje przekształcone dane. Wzorzec Input-Output dzieli zdarzenia wejściowe (tapnięcia, wprowadzanie tekstu) i stany wyjściowe (tekst przycisku, widoczność loadera). Takie podejście upraszcza testowanie: ViewModel jest testowany bez UI przez wirtualne Schedulery.
RxSwift nadaje się zarówno do małych projektów z kilkoma ekranami, jak i do dużych aplikacji enterprise z dziesiątkami modułów. W dużych projektach reaktywne łańcuchy przenikają całą architekturę: od obserwacji UserDefaults przez RxProperty po zapytania sieciowe przez Moya (nakładka RxSwift na Alamofire). Każdy moduł jest izolowany i komunikuje się przez reaktywne interfejsy, co upraszcza wymianę implementacji bez zmiany subskrybentów. Przy prawidłowej architekturze z RxSwift zmniejsza się ilość kodu w porównaniu z klasycznymi podejściami, ponieważ nie trzeba pisać boilerplate dla KVO, Target-Action czy NotificationCenter.
RxSwift jest aktywnie używany w projektach z RxDataSources — biblioteką do reaktywnej pracy z UITableView i UICollectionView. RxDataSources automatycznie oblicza różnicę między starym a nowym zestawem komórek i stosuje animowane zmiany. To uwalnia dewelopera od ręcznej pracy z beginUpdates/endUpdates i eliminuje crash przy niezgodności danych.
Do debugowania łańcuchów RxSwift istnieje operator debug() — loguje wszystkie zdarzenia: subscribe, next, error, completed, dispose. To niezbędne narzędzie przy tworzeniu złożonych reaktywnych pipeline. debug(String) przyjmuje identyfikator wyświetlany w logach. Do profilowania pamięci RxSwift.Resources.total pokazuje całkowitą liczbę aktywnych Observable i Disposable w aplikacji — pomaga wykryć wycieki, gdy DisposeBag nie jest wyczyszczony lub retain cycle utrzymuje subskrypcję. Dodatkowy operator takeUntil(self.rx.deallocated) automatycznie anuluje subskrypcję przy dealokacji obiektu — to kolejna warstwa ochrony przed wyciekami.
Podczas pisania kodu RxSwift ważne jest przestrzeganie zasady jeden Observable na subskrypcję: każdy ViewController nie powinien tworzyć więcej niż jednej subskrypcji do jednego Observable — zmniejsza to ryzyko race condition. Do memoizacji Observable używa się operatora share(), który zmienia zimny Observable w gorący z replay-buforem rozmiaru 1. Podczas pracy ze współdzielonymi zasobami używaj connect() do zarządzania rozpoczęciem emisji — gwarantuje to, że wszyscy subskrybenci połączą się przed pierwszym zdarzeniem.
Testowanie kodu RxSwift wykonuje się przez TestScheduler — wirtualny Scheduler, który umożliwia zarządzanie czasem. testScheduler.createHotObservable(values) tworzy Observable z predefiniowaną sekwencją zdarzeń według wirtualnego czasu. testScheduler.start() uruchamia przetwarzanie. TestScheduler pozwala sprawdzać, w jakiej kolejności i na jakim wirtualnym znaczniku czasu występują zdarzenia, bez rzeczywistych opóźnień, co czyni testy szybkimi i deterministycznymi.
Często zadawane pytania
Observable to zimne źródło: nie emituje zdarzeń do momentu subskrypcji. Subject jest gorący: emituje zdarzenia niezależnie od subskrybentów i umożliwia ręczne wstawianie wartości przez onNext. PublishSubject przekazuje tylko nowe zdarzenia, BehaviorSubject — ostatnie plus nowe.
DisposeBag przechowuje wszystkie Disposable subskrypcje. Gdy DisposeBag jest dealokowany (na przykład przy zamknięciu ViewController), wszystkie przechowywane subskrypcje są automatycznie anulowane. Gwarantuje to, że Observable nie wyśle już zdarzenia do zniszczonego obiektu UI.
Jeśli minimalna wersja iOS 13+ i zespół zna SwiftUI — wybierz Combine. Jeśli projekt obsługuje iOS 12 i niżej lub wymaga większego zestawu operatorów — RxSwift. Combine zapewnia lepszą integrację z Foundation (URLSession, Timer, NotificationCenter).
Schedulers abstrahują wątki wykonania. subscribeOn wskazuje, na którym Schedulerze wykonywana jest subskrypcja (zwykle background). observeOn określa, na którym Schedulerze odbierane są zdarzenia (częściej MainScheduler dla aktualizacji UI). SerialDispatchQueueScheduler działa przez GCD.
Tak, RxSwift można zintegrować ze SwiftUI przez ObservableObject. Użyj BehaviorRelay jako właściwości @Published: subskrypcja Relay transmitowana zmiany do Combine, a SwiftUI przerysowuje View przez @ObservedObject. To popularny wzorzec migracji z UIKit na SwiftUI.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również