RxSwiftは、iOS向けのリアクティブプログラミングライブラリで、Observableパターンと関数型オペレーターを実装し、非同期データストリームを扱います。ReactiveX(Rx)の概念をSwift言語に移植し、UI、ネットワークリクエスト、データベース、タイマーからのイベントを処理するための統一APIを提供します。ReactiveX、2025によると、このライブラリはGitHub上の6万以上のプロジェクトで使用されており、ネイティブCombineが登場するまではSwiftにおけるリアクティブプログラミングの標準であり続けています。RxSwiftは、デリゲート、クロージャ、通知を単一のイベント処理チェーンに置き換えます。
重要なポイント
RxSwiftは、Microsoftが2012年に.NET向けに作成したReactiveX(Rx)ライブラリのSwiftポートです。Rxの核となる考え方は、あらゆる非同期データソースをObservableシーケンスとして表現し、関数型オペレーターを適用できるようにすることです。iOS開発では、RxSwiftはUIイベント(ボタンタップ、テキスト入力、ジェスチャー)を、明示的なデリゲートやtarget-actionなしでアプリケーションロジックにバインドするために使用されます。
ライブラリは3つのモジュールで構成されています:RxSwift(コア — Observable、Operator、Scheduler)、RxCocoa(UIKit統合 — UIButton、UITextField、UITableView用のrx拡張)、RxRelay(終端イベントなしのSubject)。この分離により、コアをサーバーサイドSwiftやテストで使用し、UIラッパーはiOSアプリケーションにのみ接続できます。
Stack Overflow、2025の調査によると、RxSwiftはiOS向けのサードパーティライブラリでトップ5に入ります。その人気の主な理由は、すべての非同期パターンの統一的な処理にあります:URLSessionによるネットワークリクエスト、UIViewPropertyAnimatorによるアニメーション、NotificationCenterによる通知、DelegateProxyによるデリゲート — これらすべてが予測可能なライフサイクルを持つObservableに集約されます。
リアクティブプログラミングは、プログラムがデータの変更をポーリングするのではなく、それに反応するパラダイムです。「データを取得→処理→UIを更新」と書く代わりに、開発者は変換チェーンを記述します:「データが変わったら、フィルターを適用し、次にmap、そしてUIを更新する」。RxSwiftは、遅延実行を伴うObservableチェーンを通じてこのパラダイムを実装します — 購読者が現れるまでは何も起こりません。
ObservableはRxSwiftの基本的な型で、時間経過に伴うイベントのシーケンスを表します。Observableは3種類のイベントを送信できます:next(新しい値)、error(ストリームを終了するエラー)、completed(正常完了)。有限Observable(すべての値を送信後に完了)と無限Observable(例:UIイベント — 決して完了しない)があります。
Observableのライフサイクルには3つの段階があります:作成(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は4種類のSubjectを提供します:PublishSubject(新しいイベントのみ)、BehaviorSubject(初期値付き)、ReplaySubject(直近N件のイベントをバッファリング)、AsyncSubject(完了前の最後の値のみ)。Subjectは、命令型コード(クロージャ、デリゲート)をリアクティブチェーンに統合するのに便利です。
Disposableは購読解除トークンです。購読者がイベントを受信したくなくなった場合、disposable.dispose()を呼び出します。実際には、DisposeBagが使用されます:所有者(例:UIViewController)の初期化解除時にすべての購読を自動的に解除するDisposableのコレクションです。これにより、手動購読管理で避けられないメモリリークを防ぎます。
| Subjectの種類 | 初期値 | 購読者に再送信 | 使用例 |
|---|---|---|---|
| PublishSubject | なし | 新しいイベントのみ | UIイベント、稀な通知 |
| BehaviorSubject | あり | 最新+新規 | 状態、データストリーム |
| ReplaySubject | なし | バッファN+新規 | 履歴キャッシュ |
| AsyncSubject | なし | 最後のみ | 計算タスク |
| PublishRelay | なし | 新規のみ | エラー/完了なし |
RxSwiftのオペレーターは、1つの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を1つに結合します。combineLatestは複数のストリームからの最新値をタプルにマージし、zipは同じインデックスを持つ要素をペアにし、mergeはイベント到着順に複数のストリームを1つに結合します。withLatestFromはメインストリームからのイベントを別のストリームからの最新値と結合します — 現在の状態を持つUIイベントに便利です。
| カテゴリ | オペレーター | 説明 |
|---|---|---|
| 変換 | map | 各値を関数で変換する |
| 変換 | flatMap | ネストされたObservableを平坦なストリームに展開する |
| フィルタリング | filter | 述語で値をフィルタリングする |
| フィルタリング | distinctUntilChanged | 変更された値のみを通過させる |
| 結合 | combineLatest | 2つ以上のストリームからの最新値を結合する |
| 結合 | zip | インデックスで要素をペアにする |
| 制御 | debounce | ストリームの停止までイベントを遅延する |
| 制御 | take | 最初のN個のイベントを取得しストリームを完了する |
RxSwiftのSchedulerは、実行スレッド(またはキュー)の抽象化です。Schedulerは、イベントの作成、変換、購読がどのスレッドで実行されるかを決定します。開発者が明示的にDispatchQueueを指定するGCDとは異なり、RxSwiftは2つのパラメータを使用します:subscribeOn(どのスレッドでObservableが実行されるか)とobserveOn(どのスレッドで購読者が呼び出されるか)です。
MainSchedulerはメインスレッドでコードを実行します — UIKitの更新に必須です(すべてのUI変更はメインスレッドで行われる必要があります)。SerialDispatchQueueSchedulerはシリアルGCDキューをラップし、ConcurrentDispatchQueueSchedulerは並行キューをラップします。バックグラウンドタスクには、qos: .backgroundまたは.utilityを指定したConcurrentDispatchQueueSchedulerが使用されます。
// 典型的なパターン:バックグラウンド処理+mainでUI
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は上流全体に影響します(observeOnより前のすべてのオペレーターは指定されたスケジューラーで実行されます)。observeOnは下流を切り替えます — observeOnより後のすべてのオペレーターは指定されたスケジューラーで実行されます。チェーン内には、異なる変換段階でスレッドを切り替えるために複数のobserveOnを配置できます。
SerialDispatchQueueSchedulerはイベントの順次処理を保証し、共有リソースのスレッドセーフティにとって重要です。高負荷の操作(画像処理、JSONパース)にはConcurrentDispatchQueueSchedulerを使用してください — RxSwiftは1つのObservable内ではイベントの順序を保持しますが、異なるObservableは並行して処理される可能性があります。
RxSwiftはiOSプロジェクトで、リアクティブチェーンを介してUIをデータにバインドするために最も頻繁に使用されます。RxCocoaはすべての標準的なUIKitコンポーネントにrx拡張を提供します:UIButton用のrx.tap、UITextField用のrx.text、UIPickerView用のrx.selectedRow。これにより、@IBActionとデリゲートを放棄し、宣言的な購読に置き換えることができます。
MVVM(Model-View-ViewModel)は、ViewModelが状態とビジネスロジックを管理し、ViewがViewModelのリアクティブプロパティを購読するアーキテクチャパターンです。RxSwiftはMVVMに完全に適合します:ViewModelはデータ用のObservableまたはDriverを公開し、Viewはbindを介してそれらを購読します。ViewModelはViewへの参照を持ちません — Viewが消費するObservableを返します。
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の2番目に一般的なユースケースです。URLSession.rx.responseはHTTPリクエストをObservableにラップし、成功時には(response、data)を、失敗時にはerrorを返します。Codableとmapオペレーターを組み合わせることで、コンパクトなリアクティブAPIレイヤーが得られます:コールバックや各メソッドでのエラー処理なしのObservable<MyModel>。ネットワークエラー時には、retry(3)オペレーターが指数バックオフ付きで自動的に3回リクエストを再試行します。
Combineは、iOS 13で導入されたAppleのネイティブフレームワークです。RxSwiftと同じタスクを解決します:Publisher、Subscriber、オペレーターを介した非同期イベントの処理です。ただし、Combineには重要な違いがあります:Failure型による厳格なエラータイピング、Swift Concurrency(async/await)の組み込みサポート、@PublishedとObservableObjectを介したSwiftUIとの統合です。
RxSwiftは後方互換性で優れています — iOS 8+をサポートする一方、CombineはiOS 13+が必要です。RxSwiftはサードパーティ拡張(RxDataSources、RxGesture、RxAnimated)の豊かなエコシステムと詳細なオペレータードキュメントを持っています。古いiOSバージョンをサポートするプロジェクトでは、RxSwiftが唯一の選択肢であり続けています。
iOS 13+の新規プロジェクトでは、AppleはCombineを推奨しています。SwiftUIと緊密に統合され、バイナリサイズが小さく、公式サポートがあります。ただし、既存のRxSwiftコードをCombineに移行するには、すべてのObservable→Publisherを書き換える必要があり、RxCocoaのエコシステムには完全なCombine相当物がありません — UIKitにはすべてのUIコンポーネント用のネイティブPublisherはありません。
| 特徴 | 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コードベースがある場合、または豊富なオペレーターエコシステム(Combineの約100に対して400+)が必要な場合に選択されます。iOS 13+の新規プロジェクトではCombineが推奨されます。
DisposeBagはDisposableトークンのコレクションで、所有者の初期化解除時に自動的にすべての購読を解除します。DisposeBagがないと、購読によってクロージャへの強参照が作成され、UIViewControllerが破棄される際にメモリリークが発生します。
エラーをデフォルト値に置き換えるにはcatchError、Observableの実行を再試行するにはretry、エラーをイベントに変換するにはmaterializeを使用します。UIレイヤーでは、DriverとSignalはエラーを渡しません — 内部で処理されます。
Driverは、MainSchedulerでの実行、エラーの不在、リソース共有を保証する特別なObservable型です。DriverはUI更新がメインスレッドで行われることを保証します。Observableはそのような保証を提供しません — observeOnが必要です。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。