RxSwift — co to jest, możliwości i programowanie reaktywne

Autor: IT Sectr Opublikowano: 2026-05-03 Czas czytania: 10 min

RxSwift — to biblioteka programowania reaktywnego dla iOS, implementująca wzorzec Observable i funkcjonalne operatory do pracy z asynchronicznymi strumieniami danych. Portuje koncepcje ReactiveX (Rx) do języka Swift, dostarczając jednolity API do obsługi zdarzeń z UI, zapytań sieciowych, baz danych i timerów. Według danych ReactiveX, 2025, biblioteka jest używana w ponad 60 000 projektów na GitHub i pozostaje standardem programowania reaktywnego dla Swift aż do pojawienia się natywnego Combine. RxSwift zastępuje delegaty, domknięcia i powiadomienia jednolitym łańcuchem przetwarzania zdarzeń.

Najważniejsze

  • RxSwift — implementacja ReactiveX dla Swift, oparta na wzorcu Observable i łańcuchach operatorów
  • Observable — źródło zdarzeń asynchronicznych, które może zakończyć się sukcesem, błędem lub działać nieskończenie
  • Subject — hybryda Observable i Observer, umożliwiająca ręczne wysyłanie zdarzeń do strumienia
  • Schedulers zarządzaj na którym wątku wykonywana jest subskrypcja, obserwacja i przetwarzanie zdarzeń
  • Operatory map, flatMap, filter, combineLatest transformują i łączą strumienie bez stanów wyścigu

Czym jest RxSwift?

RxSwift — to Swift-port biblioteki ReactiveX (Rx), stworzonej przez firmę Microsoft dla .NET w 2012 roku. Główna idea Rx — przedstawić każdy asynchroniczny źródło danych jako Observable sekwencję, do której można stosować funkcjonalne operatory. W iOS-developmentie RxSwift jest używany do łączenia zdarzeń UI (naciśnięcia przycisków, wprowadzanie tekstu, gesty) z logiką aplikacji bez jawnych delegatów i target-action.

Biblioteka składa się z trzech modułów: RxSwift (rdzeń — Observable, Operator, Scheduler), RxCocoa (integracja z UIKit — rx-rozszerzenia dla UIButton, UITextField, UITableView) i RxRelay (Subject bez zdarzeń terminalnych). Taki podział pozwala używać rdzenia w serwerowym Swift i testach, podłączając UI-obudowę tylko dla aplikacji iOS.

Według ankiety Stack Overflow, 2025, RxSwift wchodzi do top-5 najczęściej używanych bibliotek zewnętrznych dla iOS. Głównym powodem popularności jest jednolita obsługa wszystkich wzorców asynchronicznych: zapytania sieciowe przez URLSession, animacje przez UIViewPropertyAnimator, powiadomienia przez NotificationCenter i delegaty przez DelegateProxy — wszystko to sprowadza się do Observable z przewidywalnym cyklem życia.

Filozofia programowania reaktywnego

Programowanie reaktywne — to paradygmat, w którym program reaguje na zmiany danych, a nie je odpytuje. Zamiast pisać „pobierz dane → przetwórz → zaktualizuj UI“, programista opisuje łańcuch transformacji: „kiedy dane się zmienią, zastosuj filtr, potem map, potem zaktualizuj UI“. RxSwift implementuje ten paradygmat poprzez Observable łańcuchy z leniwym wykonaniem — nic się nie dzieje, dopóki nie pojawi się subskrybent.

Kluczowe komponenty RxSwift: Observable, Subject, Disposable

Observable — fundamentalny typ RxSwift, reprezentujący sekwencję zdarzeń w czasie. Observable może wysyłać trzy typy zdarzeń: next (nowa wartość), error (błąd, kończący strumień) i completed (pomyślne zakończenie). Istnieją finite Observable (kończące się po wysłaniu wszystkich wartości) i infinite Observable (np. zdarzenia UI — nigdy się nie kończą).

Observable i jego cykl życia

Cykl życia Observable obejmuje trzy etapy: tworzenie (create, just, from), transformacja (operatory map, filter, flatMap) i subskrypcja (subscribe). Bez subskrypcji Observable nie wykonuje żadnych działań — to leniwa sekwencja. Po subskrypcji Observable zaczyna wysyłać zdarzenia do subskrybenta, dopóki się nie zakończy lub subskrybent nie anuluje subskrypcji przez Disposable.

swift
import RxSwift

// Tworzenie Observable z tablicy
let numbers = Observable.from([1, 2, 3, 4, 5])

// Transformacja przez operatory
let squared = numbers
    .filter { $0 % 2 == 0 }
    .map { $0 * $0 }

// Subskrypcja z obsługą zdarzeń
let disposable = squared
    .subscribe(onNext: { print($0) },
               onError: { print("Error: \($0)") },
               onCompleted: { print("Done") })

Subject — to typ, który jednocześnie jest Observable (można się na niego subskrybować) i Observer (można do niego wysyłać zdarzenia). RxSwift dostarcza cztery typy Subject: PublishSubject (tylko nowe zdarzenia), BehaviorSubject (z wartością początkową), ReplaySubject (buforowanie ostatnich N zdarzeń) i AsyncSubject (tylko ostatnia wartość przed zakończeniem). Subject jest wygodny do integracji kodu imperatywnego (domknięcia, delegaty) z reaktywnym łańcuchem.

Disposable — to token anulowania subskrypcji. Gdy subskrybent nie chce już otrzymywać zdarzeń, wywołuje disposable.dispose(). W praktyce używa się DisposeBag: kolekcji Disposable, która automatycznie anuluje wszystkie subskrypcje przy deinicjalizacji właściciela (np. UIViewController). Zapobiega to wyciekom pamięci, nieuniknionym przy ręcznym zarządzaniu subskrypcjami.

Typ SubjectWartość początkowaPowtarza subskrybentowiZastosowanie
PublishSubjectNieTylko nowe zdarzeniaZdarzenia UI, rzadkie powiadomienia
BehaviorSubjectTakOstatnie + noweStan, strumień danych
ReplaySubjectNieBufor N + noweCache’owanie historii
AsyncSubjectNieTylko ostatnieZadania obliczeniowe
PublishRelayNieTylko noweBez error/completed

Operatory transformacji i filtracji strumieni

Operatory RxSwift — to funkcje, które przyjmują jeden Observable i zwracają inny Observable, transformując strumień danych. Łącząc operatory, programista buduje deklaratywne łańcuchy przetwarzania bez zmiennych pośrednich i stanów wyścigu. Wszystkie operatory są leniwe: łańcuch buduje się podczas opisu, a wykonuje podczas subskrypcji.

Operatory transformacji zmieniają każde zdarzenie w strumieniu. map stosuje funkcję do każdego elementu, flatMap rozwija Observable z każdego elementu w jeden płaski strumień, scan akumuluje wynik pośredni (analog reduce, ale z emisją każdego kroku). buffer grupuje elementy według czasu lub ilości, window dzieli strumień na zagnieżdżone Observable według okien.

swift
// Przykład łańcucha operatorów: wyszukiwanie z 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)

Operatory filtracji przepuszczają tylko te zdarzenia, które spełniają warunek. filter odsiewa według predykatu, distinctUntilChanged przepuszcza tylko wartości różne od poprzedniej, take i takeWhile ograniczają liczbę zdarzeń. skip i skipWhile pomijają pierwsze N zdarzeń lub zdarzenia do spełnienia warunku. Do obsługi błędów używa się catchError (przechwycenie i zamiana) i retry (ponowienie sekwencji przy błędzie).

Operatory łączenia łączą kilka Observable w jeden. combineLatest łączy ostatnie wartości z kilku strumieni w krotkę, zip łączy parami elementy o tych samych indeksach, merge łączy kilka strumieni w jeden w kolejności nadejścia zdarzeń. withLatestFrom łączy zdarzenie z głównego strumienia z ostatnią wartością z innego strumienia — wygodne dla zdarzeń UI z bieżącym stanem.

KategoriaOperatorDziałanie
TransformacjamapPrzekształca każdą wartość przez funkcję
TransformacjaflatMapRozwija zagnieżdżone Observable w płaski strumień
FiltracjafilterPrzepuszcza wartości według predykatu
FiltracjadistinctUntilChangedPrzepuszcza tylko zmienione wartości
ŁączeniecombineLatestŁączy ostatnie wartości z 2+ strumieni
ŁączeniezipŁączy parami elementy według indeksu
ZarządzaniedebounceOpóźnia zdarzenia do pauzy w strumieniu
ZarządzanietakePobiera pierwsze N zdarzeń i kończy strumień

Schedulers i zarządzanie wątkami wykonania

Scheduler w RxSwift — to abstrakcja nad wątkiem wykonania (lub kolejką). Scheduler określa, na którym wątku wykonywane jest tworzenie zdarzeń, transformacja i subskrypcja. W przeciwieństwie do GCD, gdzie programista jawnie wskazuje DispatchQueue, RxSwift używa dwóch parametrów: subscribeOn (na którym wątku wykonywany jest Observable) i observeOn (na którym wątku wywoływany jest subskrybent).

MainScheduler i BackgroundScheduler

MainScheduler wykonuje kod na głównym wątku — obowiązkowy do aktualizacji UIKit (wszystkie zmiany UI muszą odbywać się na main thread). SerialDispatchQueueScheduler opakowuje sekwencyjną kolejkę GCD, ConcurrentDispatchQueueScheduler — równoległą. Do zadań w tle używa się ConcurrentDispatchQueueScheduler z qos: .background lub .utility.

swift
// Typowy wzorzec: praca w tle + UI na main
apiService.fetchData()
    .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background))
    .observeOn(MainScheduler.instance)
    .subscribe(onNext: { data in
        self.tableView.reloadData()
        self.loadingIndicator.stopAnimating()
    })
    .disposed(by: disposeBag)

Prawidłowe użycie Scheduler zapobiega blokowaniu UI przy zapytaniach sieciowych i ciężkich obliczeniach. subscribeOn wpływa na cały upstream (wszystkie operatory do observeOn wykonują się na wskazanym planiście). observeOn przełącza downstream — wszystkie operatory po observeOn wykonują się na wskazanym planiście. W łańcuchu może być wiele observeOn do przełączania między wątkami na różnych etapach transformacji.

SerialDispatchQueueScheduler gwarantuje sekwencyjne przetwarzanie zdarzeń, co jest ważne dla bezpieczeństwa wątkowego współdzielonych zasobów. Do operacji o wysokim obciążeniu (przetwarzanie obrazów, parsowanie JSON) używaj ConcurrentDispatchQueueScheduler — RxSwift zachowa kolejność zdarzeń wewnątrz jednego Observable, ale różne Observable mogą być przetwarzane równolegle.

Praktyczne zastosowanie RxSwift w iOS

RxSwift w projektach iOS najczęściej stosuje się do łączenia UI z danymi przez reaktywne łańcuchy. RxCocoa dostarcza rx-rozszerzenia dla wszystkich standardowych komponentów UIKit: rx.tap dla UIButton, rx.text dla UITextField, rx.selectedRow dla UIPickerView. Pozwala to zrezygnować z @IBAction i delegatów, zastępując je deklaratywnymi subskrypcjami.

RxSwift w połączeniu z MVVM

MVVM (Model-View-ViewModel) — wzorzec architektoniczny, w którym ViewModel zarządza stanem i logiką biznesową, a View subskrybuje reaktywne właściwości ViewModel. RxSwift idealnie wpisuje się w MVVM: ViewModel publikuje Observable lub Driver dla danych, View subskrybuje je przez bind. ViewModel nie ma referencji do View — zwraca Observable, które View konsumuje.

swift
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
            }
    }
}

// W ViewController:
viewModel.isFormValid
    .bind(to: loginButton.rx.isEnabled)
    .disposed(by: disposeBag)

Zapytania sieciowe — drugi pod względem częstotliwości obszar zastosowania RxSwift. URLSession.rx.response opakowuje zapytanie HTTP w Observable, który zwraca (response, data) przy sukcesie lub error przy niepowodzeniu. W połączeniu z Codable i operatorem map otrzymujemy zwartą reaktywną warstwę API: Observable<MyModel> bez callbacków i obsługi błędów w każdej metodzie. Przy błędzie sieci operator retry(3) automatycznie ponawia zapytanie trzykrotnie z wykładniczym opóźnieniem.

RxSwift vs Combine

Combine — natywny framework Apple, wprowadzony w iOS 13. Rozwiązuje te same zadania co RxSwift: praca ze zdarzeniami asynchronicznymi przez Publisher, Subscriber i operatory. Jednak Combine ma kluczowe różnice: ścisła typizacja błędów przez typ Failure, wbudowane wsparcie Swift Concurrency (async/await) i integracja z SwiftUI przez @Published i ObservableObject.

RxSwift wygrywa w kompatybilności wstecznej — obsługuje iOS 8+, podczas gdy Combine wymaga iOS 13+. RxSwift ma bogatszy ekosystem rozszerzeń zewnętrznych (RxDataSources, RxGesture, RxAnimated) i szczegółową dokumentację operatorów. Dla projektów ze wsparciem starszych wersji iOS RxSwift pozostaje jedynym wyborem.

Dla nowych projektów z iOS 13+ Apple zaleca Combine. Jest ściśle zintegrowany z SwiftUI, ma mniejszy rozmiar binarny i oficjalne wsparcie. Jednak migracja istniejącego kodu RxSwift do Combine wymaga przepisania wszystkich Observable → Publisher, a ekosystem RxCocoa nie ma pełnego odpowiednika w Combine — UIKit nie ma natywnych Publisher dla wszystkich komponentów UI.

CechaRxSwiftCombine
Minimalne iOSiOS 8+iOS 13+
Typ błęduError (dowolny)Generic Failure
Rozszerzenia UIRxCocoa (UIKit, AppKit)@Published (SwiftUI)
Operatory400+ operatorów~100 operatorów
Swift ConcurrencyPrzez bridgeNatywne wsparcie
StatusZewnętrznaApple oficjalnie

Często zadawane pytania

Jaka jest różnica między Observable a Subject w RxSwift?

Observable — źródło zdarzeń z leniwym wykonaniem. Subject jednocześnie jest Observable i Observer — możesz się na niego subskrybować i wysyłać do niego nowe zdarzenia ręcznie. Subject jest wygodny do integracji kodu imperatywnego z reaktywnymi łańcuchami.

Kiedy używać RxSwift zamiast Combine?

RxSwift wybiera się przy potrzebie wsparcia iOS 11-12, przy istniejącej bazie kodu RxSwift lub przy potrzebie bogatego ekosystemu operatorów (400+ wobec ~100 w Combine). Dla nowych projektów na iOS 13+ preferowany jest Combine.

Czym jest DisposeBag i do czego służy?

DisposeBag — kolekcja tokenów Disposable, automatycznie anulująca wszystkie subskrypcje przy deinicjalizacji właściciela. Bez DisposeBag subskrypcja tworzy silną referencję na domknięcie, co prowadzi do wycieku pamięci przy zniszczeniu UIViewController.

Jak obsługiwać błędy w RxSwift?

Używaj catchError do zastąpienia błędu wartością domyślną, retry do ponownego wykonania Observable, materialize do przekształcenia błędu w zdarzenie. W warstwie UI Driver i Signal nie przekazują błędów — są obsługiwane wewnętrznie.

Czym Driver różni się od Observable w RxCocoa?

Driver — to specjalny typ Observable, gwarantujący wykonanie na MainScheduler, brak błędów i współdzielenie zasobów. Driver gwarantuje, że aktualizacje UI odbywają się na głównym wątku. Observable nie daje takich gwarancji — wymaga observeOn.

Podsumowanie

  • RxSwift — biblioteka programowania reaktywnego dla iOS, implementująca wzorzec Observable i 400+ operatorów transformacji
  • Observable, Subject, Disposable — trzy fundamentalne typy stanowiące podstawę wszystkich reaktywnych łańcuchów
  • Operatory map, flatMap, filter, combineLatest, debounce pozwalają budować deklaratywne łańcuchy bez stanów wyścigu
  • Schedulers (subscribeOn / observeOn) zarządzają wątkami wykonania, zapobiegając blokowaniu UI
  • RxCocoa dostarcza rx-rozszerzenia dla UIKit, zastępujące delegaty i target-action reaktywnymi subskrypcjami
  • Combine — natywna alternatywa od Apple dla iOS 13+, ale RxSwift pozostaje aktualny dla starszych wersji

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.

Omów projekt

Przeczytaj również