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

# はじめに

[ReactiveSwift](https://github.com/ReactiveCocoa/ReactiveSwift)の基本コンポーネントの、基本的な使い方について記述します。
（そもそもReactiveSwiftとは何か？、という話は[補足](#reactiveswift%E3%81%A8%E3%81%AF)参照）


## 対象読者
- Functional Reactive Programming（以下FRP）のコンセプトは把握した  
（コンセプトについては、[【翻訳】あなたが求めていたリアクティブプログラミング入門](http://ninjinkun.hatenablog.com/entry/introrxja)を読むことをオススメします。）
- `Signal`/`SignalProducer` などを、どう生成・使用できるか分からない
- playgroundやソースを全部読むのは多すぎて、実際に使う基礎を知りたい
- UI bindingではなく、Observableの基礎を知りたい

## 環境
- [ReactiveSwift1.0.0](https://github.com/ReactiveCocoa/ReactiveSwift/releases/tag/1.0.0)


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

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

`Signal`と`SignalProducer`をあわせてObservableと呼びます。

## `Signal`
`Signal`は、Hot Observableのことです。
※Hot/Coldという概念については、[このあたり](https://github.com/ReactiveCocoa/ReactiveSwift#signals-and-signalproducers-hot-and-cold-observables)を参考にしてください。

### 作る
いくつかありますが、頻繁に使用する`.pipe`での作り方を紹介します。

```swift
let (signal, innerObserver) = Signal<Int, NSError>.pipe()
```

### observeする（ = Observerを登録する）
（Observerは、本質的にはEventを受け取るクロージャーです）
詳しくは[補足](#observer--closure)参照

```swift
signal.observeResult { result in
    switch result {
    case let .success(value):
        print("value: \(value)")
    case let .failure(error):
        print("error: \(error)")
    }
}
```
`NoError`の`Signal`であれば、`.observeValues`で、Valueのみを受け取るクロージャーを登録することもできます。

### 値を送信する
```swift
innerObserver.send(value: 1)
```
これで、Observerとして登録したクロージャーが実行されます。

### いつ使うか？
Hot Observableがほしいときに使います。
（NSNotification的な使い方など）


## `SignalProducer`
`SignalProducer`はCold Observableのことです。

### 作る
こちらも、いくつかinitializerがありますが、ここでは、`startHandler`を使った方法を紹介します。（最もよく使うと思います。）

```swift
let signalProducer = SignalProducer<Int, MyError> { (innerObserver, disposable) in
    innerObserver.send(value: 1)
    innerObserver.sendCompleted()
}
```

trailing closureとして渡しているclosureが、`startHandler`と呼ばれるもので、`.start()`を呼んだ際に実行されるものです。（詳しいフローは次の項参照）


### startする
`SignalProducer`は、startすることで使用します。

```swift
signalProducer.startWithResult { result in
    switch result {
    case let .success(value):
        print("value: \(value)")
    case let .failure(error):
        print("error: \(error)")
    }
}
```
ここでは、以下のようなフローで処理が行われます。

1. `Signal`が生成される  
内部的には`.pipe()`が使用されている
1. 1で生成された`Signal`にobserverが登録される  
`startWithResult`で渡されたclosureを引数として、生成された`Signal`の`observeResult`が実行される、というイメージ
1. `startHandler`が実行される  
引数の`innerObserver`には、1で生成された`Signal`の`innerObserver`が渡されてくる

なお、 `Signal`と同様に、`NoError`のSignalProducerの場合は、`startWithValues`というメソッドでstartすることもできます。

他にも、以下のようなstartメソッドがあります。

```swift
signalProducer.start() // フローの2はおこらない
```

```swift
signalProducer.startWithSignal { (signal, disposable) in
    print("You can access created signal here")
} // 生成されたSignal（HotObservable)を受け取る
```

### いつ使うか？
例えば、ネットワークリクエストを`startHandler`内に書いておけば、startすることでネットワークリクエストを実施し、その結果をobserveすることが可能になります。

```swift
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`）となってしまえば、あとはオペレーターをつないで記述していくことで、ロジックを記述することができます。

各種オペレーターは`.` でつなげて書きます。

```swift
signal.map { }
```

# 今後
以下のコンポーネントについて記述する予定です。

- `Property` / `MutableProperty`
- `Action`


# 補足
## ReactiveSwiftとは
ReactiveSwiftは、swiftでFunctional Reactive Programming（以下FRP）を実現するライブラリの1つです。
※ ReactiveCocoa（以下RAC）という名前で知られていましたが、RAC5でリポジトリの整理が行われ、FRPを実現する基本コンポーネントはReactiveSwiftに含まれる（分離される）こととなりました。[参考](https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/CHANGELOG.md#repository-split)

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の関係性とほぼ同じです。

[参考](https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/CHANGELOG.md#repository-split)

## Observer = closure
Observerは、本質的には、以下のようなclosureです。（closureの薄いラッパーです）

```swift
(Event<Value, Error>) -> Void
```
参考：　https://github.com/ReactiveCocoa/ReactiveSwift/blob/master/Sources/Observer.swift

### Event
Eventとは、以下のようなenumです。

```swift
// とても簡略化したものです
enum Event<Value, Error: Swift.Error> {
	case value(Value)
	case failed(Error)
	case completed
	case interrupted
}
```

「observeする」というのは、このclosureをobservable（`Signal`/`SignalProducer`）に登録する処理のことです。

# 参考資料
## FRPのコンセプトを知る
- [【翻訳】あなたが求めていたリアクティブプログラミング入門](http://ninjinkun.hatenablog.com/entry/introrxja)  
  コンセプトを知るのにはこちらの資料がよいです。
- [川で例えずに理解するObservable](https://speakerdeck.com/yoching/chuan-deli-ezunili-jie-suruobservable)  
  私が理解した方法をざっくりまとめたものです。

## ReactiveSwift（ReactiveCocoa）を知る
- [ReactiveCocoa4.1入門](https://speakerdeck.com/nirma/reactivecocoa-4-dot-1ru-men)
- [Getting Started with ReactiveCocoa v4.1.0](https://speakerdeck.com/inamiy/getting-started-with-reactivecocoa-v4-dot-1-0)
- [Recent State of ReactiveCocoa](https://speakerdeck.com/ikesyo/recent-state-of-reactivecocoa)
- 仕様を把握するには、[ReactiveSwift](https://github.com/ReactiveCocoa/ReactiveSwift)の**テストコード**を読むのがオススメです。Issueを検索するのもよいです。

## ReactiveSwift（ReactiveCocoa）の使い方を知る
- [RACNest](https://github.com/RACCommunity/RACNest)  
シンプルなサンプルとしては、これが分かりやすいです。　※未swift3対応
- [ReactiveCocoaCatalog](https://github.com/inamiy/ReactiveCocoaCatalog)