はじめに
ReactiveSwiftの基本コンポーネントの、基本的な使い方について記述します。
(そもそもReactiveSwiftとは何か?、という話は補足参照)
対象読者
- Functional Reactive Programming(以下FRP)のコンセプトは把握した
(コンセプトについては、【翻訳】あなたが求めていたリアクティブプログラミング入門を読むことをオススメします。) -
Signal
/SignalProducer
などを、どう生成・使用できるか分からない - playgroundやソースを全部読むのは多すぎて、実際に使う基礎を知りたい
- UI bindingではなく、Observableの基礎を知りたい
環境
ReactiveSwiftのリポジトリ中に、Sandboxのplaygroundがあるので、そこに書いて試してみるのがよいでしょう。
基本コンポーネントの使い方
Signal
とSignalProducer
をあわせてObservableと呼びます。
Signal
Signal
は、Hot Observableのことです。
※Hot/Coldという概念については、このあたりを参考にしてください。
作る
いくつかありますが、頻繁に使用する.pipe
での作り方を紹介します。
let (signal, innerObserver) = Signal<Int, NSError>.pipe()
observeする( = Observerを登録する)
(Observerは、本質的にはEventを受け取るクロージャーです)
詳しくは補足参照
signal.observeResult { result in
switch result {
case let .success(value):
print("value: \(value)")
case let .failure(error):
print("error: \(error)")
}
}
NoError
のSignal
であれば、.observeValues
で、Valueのみを受け取るクロージャーを登録することもできます。
値を送信する
innerObserver.send(value: 1)
これで、Observerとして登録したクロージャーが実行されます。
いつ使うか?
Hot Observableがほしいときに使います。
(NSNotification的な使い方など)
SignalProducer
SignalProducer
はCold Observableのことです。
作る
こちらも、いくつかinitializerがありますが、ここでは、startHandler
を使った方法を紹介します。(最もよく使うと思います。)
let signalProducer = SignalProducer<Int, MyError> { (innerObserver, disposable) in
innerObserver.send(value: 1)
innerObserver.sendCompleted()
}
trailing closureとして渡しているclosureが、startHandler
と呼ばれるもので、.start()
を呼んだ際に実行されるものです。(詳しいフローは次の項参照)
startする
SignalProducer
は、startすることで使用します。
signalProducer.startWithResult { result in
switch result {
case let .success(value):
print("value: \(value)")
case let .failure(error):
print("error: \(error)")
}
}
ここでは、以下のようなフローで処理が行われます。
-
Signal
が生成される
内部的には.pipe()
が使用されている - 1で生成された
Signal
にobserverが登録される
startWithResult
で渡されたclosureを引数として、生成されたSignal
のobserveResult
が実行される、というイメージ -
startHandler
が実行される
引数のinnerObserver
には、1で生成されたSignal
のinnerObserver
が渡されてくる
なお、 Signal
と同様に、NoError
のSignalProducerの場合は、startWithValues
というメソッドでstartすることもできます。
他にも、以下のようなstartメソッドがあります。
signalProducer.start() // フローの2はおこらない
signalProducer.startWithSignal { (signal, disposable) in
print("You can access created signal here")
} // 生成されたSignal(HotObservable)を受け取る
いつ使うか?
例えば、ネットワークリクエストをstartHandler
内に書いておけば、startすることでネットワークリクエストを実施し、その結果をobserveすることが可能になります。
let someRequest = SignalProducer<Void, NSError> { (innerObserver, disposable) in
sendRequest(request) { result in
switch result {
case .success(value):
innerObserver.send(value: value)
innerObserver.sendCompleted()
case .failure(error):
innerObserver.send(error: error)
}
}
オペレーターの適用
一旦Observable(Signal
/SignalProducer
)となってしまえば、あとはオペレーターをつないで記述していくことで、ロジックを記述することができます。
各種オペレーターは.
でつなげて書きます。
signal.map { }
今後
以下のコンポーネントについて記述する予定です。
-
Property
/MutableProperty
Action
補足
ReactiveSwiftとは
ReactiveSwiftは、swiftでFunctional Reactive Programming(以下FRP)を実現するライブラリの1つです。
※ ReactiveCocoa(以下RAC)という名前で知られていましたが、RAC5でリポジトリの整理が行われ、FRPを実現する基本コンポーネントはReactiveSwiftに含まれる(分離される)こととなりました。参考
FRPは学習コストが高いと言われますが、ReactiveSwift(ReactiveCocoa)は、さらに以下のような事情があります。
- Objective-C時代からあるライブラリのため、検索するとObjective-Cの記事がヒットすることが多い
- swiftの記事が見つかっても、swift自体の破壊的変更によって、swift3では動かないことが多い
- RACはバージョンによって書き方が大きく変わっている
- 日本語の資料は少ない
自分自身、学習した際に、概念を説明する資料は多くても、実際にライブラリをどう使ったらいいかが分からず、かといって中のソースコードを読むのは(難易度・量的に)難しく、苦労しました。
この記事は、実際に使うコンポーネントに絞り、基本的な使い方のみ記述します。
ReactiveCocoa(RAC)とReactiveSwift
RAC5では、RAC4以前のReactiveCocoaとRex(UIKit拡張を提供していた別ライブラリ)が、大まかに以下のように整理し直されました。
- ReactiveCocoa: UIKit拡張(Rexで提供されていたもの)
- ReactiveSwift: FRPの基本コンポーネント
※ReactiveCocoaはReactiveSwiftに依存しています。
RxSwiftとRxCocoaの関係性とほぼ同じです。
Observer = closure
Observerは、本質的には、以下のようなclosureです。(closureの薄いラッパーです)
(Event<Value, Error>) -> Void
参考: https://github.com/ReactiveCocoa/ReactiveSwift/blob/master/Sources/Observer.swift
Event
Eventとは、以下のようなenumです。
// とても簡略化したものです
enum Event<Value, Error: Swift.Error> {
case value(Value)
case failed(Error)
case completed
case interrupted
}
「observeする」というのは、このclosureをobservable(Signal
/SignalProducer
)に登録する処理のことです。
参考資料
FRPのコンセプトを知る
-
【翻訳】あなたが求めていたリアクティブプログラミング入門
コンセプトを知るのにはこちらの資料がよいです。 -
川で例えずに理解するObservable
私が理解した方法をざっくりまとめたものです。
ReactiveSwift(ReactiveCocoa)を知る
- ReactiveCocoa4.1入門
- Getting Started with ReactiveCocoa v4.1.0
- Recent State of ReactiveCocoa
- 仕様を把握するには、ReactiveSwiftのテストコードを読むのがオススメです。Issueを検索するのもよいです。
ReactiveSwift(ReactiveCocoa)の使い方を知る
-
RACNest
シンプルなサンプルとしては、これが分かりやすいです。 ※未swift3対応 - ReactiveCocoaCatalog