Edited at

ReactiveSwift 基本要素の使い方 Signal / SignalProducer編

More than 1 year has passed since last update.


はじめに

ReactiveSwiftの基本コンポーネントの、基本的な使い方について記述します。

(そもそもReactiveSwiftとは何か?、という話は補足参照)


対象読者


  • Functional Reactive Programming(以下FRP)のコンセプトは把握した

    (コンセプトについては、【翻訳】あなたが求めていたリアクティブプログラミング入門を読むことをオススメします。)


  • Signal/SignalProducer などを、どう生成・使用できるか分からない

  • playgroundやソースを全部読むのは多すぎて、実際に使う基礎を知りたい

  • UI bindingではなく、Observableの基礎を知りたい


環境

ReactiveSwiftのリポジトリ中に、Sandboxのplaygroundがあるので、そこに書いて試してみるのがよいでしょう。


基本コンポーネントの使い方

SignalSignalProducerをあわせて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)")
}
}

NoErrorSignalであれば、.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)")
}
}

ここでは、以下のようなフローで処理が行われます。



  1. Signalが生成される

    内部的には.pipe()が使用されている

  2. 1で生成されたSignalにobserverが登録される

    startWithResultで渡されたclosureを引数として、生成されたSignalobserveResultが実行される、というイメージ


  3. startHandlerが実行される

    引数のinnerObserverには、1で生成されたSignalinnerObserverが渡されてくる

なお、 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のコンセプトを知る


ReactiveSwift(ReactiveCocoa)を知る


ReactiveSwift(ReactiveCocoa)の使い方を知る