ReactorKit(Flux + Reactive Programming)を学ぶ1 入門編


![6aa05998-26da-11e7-9b85-e48bec938a6e.png](https://qiita-image-store.s3.amazonaws.com/0/16700/9d1e6159-771c-8c6c-56b2-d7607f2dac7a.png "6aa05998-26da-11e7-9b85-e48bec938a6e.png")

# ReactorKitを学ぶシリーズ

1. [ReactorKit(Flux + Reactive Programming)を学ぶ1 入門編](http://qiita.com/yusuga/items/e793963ff51ee493497a) ← 今ここ
2. [ReactorKit(Flux + Reactive Programming)を学ぶ2 基礎編](http://qiita.com/yusuga/items/cf08cf172c92364c1e14)
3. [ReactorKit(Flux + Reactive Programming)を学ぶ3 実践編](https://qiita.com/yusuga/items/0ed5a7c918c0680828dd)

# 更新履歴

### 2018-03-28

- [v0.4.5](https://github.com/ReactorKit/ReactorKit/tree/0.4.5)から[v1.1.0](https://github.com/ReactorKit/ReactorKit/tree/1.1.0)に内容を更新
    - [StoryboardViewプロトコル](https://github.com/ReactorKit/ReactorKit/blob/1.1.0/Sources/ReactorKit/StoryboardView.swift)について追記
    - サンプルの[Counter](https://github.com/ReactorKit/ReactorKit/tree/master/Examples/Counter)の解説部分を最新の内容に合わせて更新

### 2017-06-10

- 初稿

# この記事で学べること

- ReactorKitの概要
- ReactorKitの最低限の実装
- [ReactorKit/Examples/Counter/](https://github.com/ReactorKit/ReactorKit/tree/master/Examples/Counter)の解説

*※ この記事は、[ReactorKit v1.1.0](https://github.com/ReactorKit/ReactorKit/tree/1.1.0)を元に書いています。*

# ReactorKitとは

[ReactorKit](https://github.com/ReactorKit/ReactorKit)は、リアクティブで単方向ストリームのアーキテクチャを構築するためのフレームワークです。

アーキテクチャ名は、`The Reactive Architecture`です。ReactorKitで構築できるアーキテクチャが`The Reactive Architecture`ということなのですが、便宜上、`ReactorKit` == `The Reactive Architecture`ということで説明します。

2017/1/7に公開された新しめのアーキテクチャ & フレームワークです。詳しくは後述しますが、[Flux](http://facebook.github.io/flux/)と[Reactive Programming](http://ninjinkun.hatenablog.com/entry/introrxja)([RxSwift](https://github.com/ReactiveX/RxSwift))を組み合わせて構築するアーキテクチャで、新しい概念や技術で1から作られたものではありませんので、現段階でも実用に耐えられる作りとなっています。実例として現在App Storeで公開されているの [Dribbbleアプリ](https://itunes.apple.com/us/app/drrrible/id1229592223?mt=8)は、ReactorKitを使用しており、実装はGitHubに[公開](https://github.com/devxoul/Drrrible)されています。

ReactorKitは、2018/3/28の時点でGitHubのStarは951です。
開発者の方は、[@devxoul](https://github.com/devxoul)さんで、様々なOSSを開発されている方です。

- [Then](https://github.com/devxoul/Then) ⭐️ 1,666
- [URLNavigator](https://github.com/devxoul/URLNavigator) ⭐️ 1,159
- [Toaster](https://github.com/devxoul/Toaster) ⭐️ 756
- [SwiftyImage](https://github.com/devxoul/SwiftyImage) ⭐️ 612
- [RxKeyboard](https://github.com/RxSwiftCommunity/RxKeyboard) ⭐️ 444

# 何を解決したいのか

個人的にですが、各アーキテクチャには次のような問題点を感じています。

- MVC
    - [Controllerが肥大化](https://news.realm.io/jp/news/andy-matuschak-refactor-mega-controller/)しがち
- MVVM
    - アプリの規模が大きくなるとViewModelの初期化、Observableストリームが複雑になる
- [Clean Architecture](http://qiita.com/koutalou/items/07a4f9cf51a2d13e4cdc)、[VIPER](http://qiita.com/YKEI_mrn/items/67735d8ebc9a83fffd29)
    - 正しくアーキテクチャを構築するための学習コスト
    - [抽象化によるラビオリコードの問題](https://news.realm.io/jp/news/andy-matuschak-refactor-mega-controller/)(リンク先のQ&Aの部分)

詳しくは、[iOSアプリのアーキテクチャについて考える](https://speakerdeck.com/yusuga/iosapurifalseakitekutiyanituitekao-eru)をご覧ください。

ReactorKitは、これらの問題を **良いバランスで解決** できそうだと感じています。

一つだけ強調しておきたいことは、この記事は **各アーキテクチャの優劣について話しているわけではありません。** どのアーキテクチャを選択するかは、各プロジェクトの要件や規模によりますし、実装者の好みもあると思います。結局は何か処理してそれを画面に表示するということは変わらず、それをどういう枠組みで整理するかということですしね。

# 前提知識

ReactorKitは、[RxSwift](https://github.com/ReactiveX/RxSwift)に依存しています。単方向ストリームの構築部分もそうなのですが、使う側が実装するロジック部分もRxSwiftが必須になっています。

RxSwiftはとても学習コストが高いのですが、学ぶ価値は大いにあります。
RxSwiftについては次の資料が参考になると思います。

- 概要
	- [【翻訳】あなたが求めていたリアクティブプログラミング入門](http://ninjinkun.hatenablog.com/entry/introrxja)
	- [iOSアプリ開発におけるRxSwiftの活用](https://news.realm.io/jp/news/tryswift-Marin-Todorov-I-create-iOS-apps-is-RxSwift-for-me/)
- 公式ドキュメント
	- [ReactiveX - Introduction](http://reactivex.io/documentation/operators.html)
	- [RxMarbles](http://rxmarbles.com)
	- [RxSwift Reference](http://cocoadocs.org/docsets/RxSwift/)
- 実装
	- [オブザーバーパターンから始めるRxSwift入門](http://qiita.com/k5n/items/17f845a75cce6b737d1e)
		- 長いですがシリーズ通して読めばある程度わかるようになります。
	- [RxSwift コードリーディングの勘所@社内RxSwift勉強会](https://www.slideshare.net/yukitakahashi3139241/rxswift-rxswift)
		- RxSwift v2.5.0での解説ですが、source/subscribe/run/on/Sinkなど内部実装を読み解くヒントになります。

# ReactorKitの特徴

ReactorKitの特徴は、ReactorKitがアーキテクチャの枠組みを用意してくれるので、ReactorKitのルールを守り実装を行えばアーキテクチャを導入できるという点です。アーキテクチャの枠組みが用意され、何をどこに実装するかが明確なので**アーキテクチャを正しく構築するための実装上の迷いが軽減されます。**

メインの実装は、[Reactorプロトコル](https://github.com/ReactorKit/ReactorKit/blob/master/Sources/Reactor.swift)と[Viewプロトコル](https://github.com/ReactorKit/ReactorKit/blob/master/Sources/View.swift)の2つで、非常に軽量なフレームワークです。

**※ [v0.6.0](https://github.com/ReactorKit/ReactorKit/releases/tag/0.6.0)で、StoryboardからUIViewControllerを生成しているView用に使用する[StoryboardViewプロトコル](https://github.com/ReactorKit/ReactorKit/blob/1.1.0/Sources/ReactorKit/StoryboardView.swift)が追加されました。**

# ReactorKitの実装

ReactorKitは、[Flux](http://facebook.github.io/flux/)と[Reactive Programming](http://ninjinkun.hatenablog.com/entry/introrxja)([RxSwift](https://github.com/ReactiveX/RxSwift))を組み合わせた、アクティブで単方向のストリームを実現しています。

![a91c1688-2321-11e7-8f04-bf91031a09dd.png](https://qiita-image-store.s3.amazonaws.com/0/16700/985605f7-c569-21dd-ebc9-8773c8629a9c.png "a91c1688-2321-11e7-8f04-bf91031a09dd.png")

## Actionとは

- Actionはユーザの操作を表します。
- ViewがActionを発行します。

```swift:Actionの例
enum Action {
  case refresh // 更新
  case toggleEditing // 編集モードを切り替える
  case toggleTaskDone(IndexPath) // タスクの完了を切り替える
  case deleteTask(IndexPath) // タスクを削除する
  case moveTask(IndexPath, IndexPath) // タスクを移動する
}
```

## Stateとは

- StateはViewの現在の状態を表し、具体的な値を保持します。
- ViewはStateの状態からUIを更新します。

```swift:Stateの例
struct State {
  var isEditing: Bool // 編集モードか
  var sections: [TaskListSection] // タスク(モデルデータ)の配列
}
```

## Reactorとは

- Reactorは、Viewの状態を管理するUIに依存しないレイヤー(層)です。そのためReactorでは**UIKitをimportしてはいけません**。
- 最も重要な役割は、Viewの制御フローを分離することで、すべてのViewには対応するReactorがあり、すべてのビジネスロジックをReactorに移譲します。
- ReactorはUIに依存しないため簡単にテスト可能です。
- Reactorを実装するための[Reactorプロトコル](https://github.com/ReactorKit/ReactorKit/blob/master/Sources/Reactor.swift)が定義されています。

## Viewとは

- Viewはデータを表示するところです。
- テーブルビューを例にすると、UITableViewControllerやUITableViewCellはViewにあたります。
- Viewはユーザのインプット(テキスト入力やボタンをタップしたなど)でAction発行し、Reactorの単方向ストリームにバインドします。
- ViewはStateとUIコンポーネントをバインドし、UIを更新します。
- Viewを実装するための[Viewプロトコル](https://github.com/ReactorKit/ReactorKit/blob/master/Sources/View.swift)が定義されています。


## 単方向ストリームとは

- 単方向ストリームとは、`View → Action → State → View`の流れを指します。
    1. ViewはユーザのインプットをきっかけにActionを発行する
    2. ReactorはActionを受けてStateを更新する
    3. ViewはStateとUIをバインドし、Stateの変化に応じてUIを更新する

# Reactorの処理

Reactorは、Viewから発行されたActionから最終的にはStateを更新するのですが、その中間の状態としてMutationがあります。

![2de21a28-23e2-11e7-8a41-d33d199dd951.png](https://qiita-image-store.s3.amazonaws.com/0/16700/40abeeb3-51aa-0f45-4dac-2a5a0eac2538.png "2de21a28-23e2-11e7-8a41-d33d199dd951.png")

## Mutationとは

- MutationはStateの更新内容を表します。
- MutationはReactor内部でのみ使用されます。

```swift:Mutationの例
enum Mutation {
  case toggleEditing // 編集モードを切り替える
  case setSections([TaskListSection]) // タスクをセットする
  case insertSectionItem(IndexPath, TaskListSection.Item) // タスクを挿入する
  case updateSectionItem(IndexPath, TaskListSection.Item) // タスクを更新する
  case deleteSectionItem(IndexPath) // タスクを削除する
  case moveSectionItem(IndexPath, IndexPath) // タスクを移動する
}
```

## Reactor内のデータの流れ

- Reactor内では、`Action → Mutation → State`とデータの変更を行います。
- Reactorには各状態を変更するメソッドが用意されています。
    - ActionをMutationに変更する`mutate(action:)`メソッド
    - MutationからStateを生成する`reduce(state:mutation:)`メソッド

## Serviceとは

ReactorKitには**ビジネスロジックを行うためのServiceレイヤー**が設けられています。Serviceレイヤーは必須ではないのと、今回はまずはシンプルなReactorKitの実装解説を目指しているので、Serviceレイヤーについてはまたの機会に解説を行います。

# ReactorKitの実装

ReactorKitの実装は、ReactorプロトコルとViewプロトコルに準拠し、Stateストリームを構築することです。

## Reactorプロトコルへの準拠

[Reactorプロトコル](https://github.com/ReactorKit/ReactorKit/blob/master/Sources/Reactor.swift)は次の通りです。

- 新たにStateストリームという用語が出ていますが、前述の`単方向ストリーム` == `Stateストリーム`になります。各コメントは私の意訳+補足を追加しています。気になる方は原文をご覧ください。

```swift:Reactorプロトコル
public typealias _Reactor = Reactor
public protocol Reactor: class, AssociatedObjectStore {
  associatedtype Action
  associatedtype Mutation = Action
  associatedtype State

  /// Viewからのアクション。ユーザが発行するActionをこのSubjectにバインドします。
  /// ActionSubjectはReactorKitが実装しているSubjectで`.next`のみ発行します。
  var action: ActionSubject<Action> { get }

  /// Stateの初期値です。
  var initialState: State { get }

  /// 現在のStateです。ストリームによって変更されます。
  var currentState: State { get }

  /// Stateストリームです。このObservableでStateの変更をObserveできます。
  var state: Observable<State> { get }

  /// Actionのグローバルな変更を行うことができます。このメソッドは他のObservablesとの結合に使用できます。
  /// このメソッドはActionが発行された直後、`mutate(action:)`の直前に呼び出されます。
  func transform(action: Observable<Action>) -> Observable<Action>

  /// ActionからMutationを確定させます。ここでは非同期タスクなど副作用を伴う処理を実行するのに適しています。
  /// このメソッドはActionが発行されるたびに呼び出されます。
  func mutate(action: Action) -> Observable<Mutation>

  /// Mutationのグローバルな変更を行うことができます。このメソッドは他のObservablesとの変換または結合に使用できます。
  /// このメソッドは`mutate(action:)`の直後、`reduce(state:)`の直前に呼び出されます。
  func transform(mutation: Observable<Mutation>) -> Observable<Mutation>

  /// 前回のStateとMutationから新しいStateを生成します。ここでは副作用を起こすべきではありません。
  /// このメソッドはMutationが発行されるたびに呼び出されます。
  func reduce(state: State, mutation: Mutation) -> State

  /// Stateのグローバルな変更を行うことができます。このメソッドでロギングなどの副作用を実行することもできます。
  /// このメソッドは`reduce(state:mutation:)`の直後、新しいStateがcurrentStateに適用される直前に呼び出されます。
  func transform(state: Observable<State>) -> Observable<State>
}
```

最低限実装すべきものは次の通りです。

| 定義 | 説明 | 最適な型 |
| :---: | --- | :---: |
| Action | Viewが行うアクション | 列挙型 |
| Mutation | Actionに対する変更内容 | 列挙型 |
| State | Viewの状態(具体的な値を保持) | 構造体 |
| initialState | Stateの初期値 | State型 |

| メソッド | 説明 | ルール |
| :---: | --- | :---: |
| mutate(action:) | ActionからMutationを生成する | 非同期処理などの副作用を伴う処理が可能 |
| reduce(state:) | MutationからStateを生成する | 同期処理のみを行い副作用を伴う処理は行わない |

- `transform`系は少し特殊な処理を受け持ち、複数のReactor間に影響する処理の対応に使用します。これは今回の例では使わないのでまたの機会に解説します。

## Viewプロトコルへの準拠

[Viewプロトコル](https://github.com/ReactorKit/ReactorKit/blob/1.1.0/Sources/ReactorKit/View.swift)は次の通りです。

```swift:Viewプロトコル
public typealias _View = View
public protocol View: class, AssociatedObjectStore {
  associatedtype Reactor: _Reactor

  /// RxSwiftでおなじみのDisposeBagです。
  /// 注意点として`reactor`が割り当てられるたびに新しく生成されます。
  var disposeBag: DisposeBag { get set }
  
  /// Viewが使用するReactorです。
  /// このプロパティに新しいReactorが割り当てられると、`bind(reactor:)`が呼び出されます。
  var reactor: Reactor? { get set }

  /// ViewとReactor間の各バインディングを記述するところです。
  /// `reactor`プロパティが割り当てられると呼び出されます。
  /// 注意点として、このメソッドは内部で自動で呼び出されるもので、直接呼び出してはいけません。
  func bind(reactor: Reactor)
}
```

- `disposeBag`を定義し、ViewとReactor間の各バインディングを`bind(reactor:)`に実装します。
- `bind(reactor:)`は新しいReactorが割り当てられると内部で呼び出されるため、**直接呼び出してはいけません**。

### StoryboardViewプロトコルについて

- StoryboardからUIViewControllerを生成しているView用に使用する[StoryboardViewプロトコル](https://github.com/ReactorKit/ReactorKit/blob/1.1.0/Sources/ReactorKit/StoryboardView.swift)が設けられています。

```swift:StoryboardViewプロトコル
public protocol StoryboardView: View, _ObjCStoryboardView {
}
```

- StoryboardViewプロトコルはViewプロトコルを継承しているだけで、追加の実装はありません。
- Viewプロトコルとの違いは内部で呼び出されている `bind(reactor:)` の呼び出しタイミングです。 `bind(reactor:)` は、reactorがセットされたタイミングで内部的に呼び出されるのですが、StoryboardからUIViewControllerを生成すると、initの段階ではStoryboard上で追加してあるsubViewはまだ生成されていないため、もしも `bind(reactor:)` でそれらのsubViewにアクセスするとランタイムエラーが発生します。そのためViewプロトコルしかないときは、subViewの生成タイミングを考慮してreactorのセットを遅らせたりする必要があり非常に煩雑だったのですが、StorybarodViewプロトコルでは `bind(reactor:)` の呼び出しタイミングが `ViewDidLoad()` 以降のタイミングになるように[調整](https://github.com/ReactorKit/ReactorKit/blob/1.1.0/Sources/ReactorKitRuntime/ReactorKitRuntime.m#L33)され、reactorのセットタイミングの問題が解消されています。

# サンプルアプリCounterを解説

実装はサンプルを見るのが一番わかりやすいので、ReactorKitのExamplesにある[Counter](https://github.com/ReactorKit/ReactorKit/tree/master/Examples/Counter)を例に各コードを解説していきます。

![30179038-0ba51cdc-93d9-11e7-95e4-9fb3000c6c3f.png](https://qiita-image-store.s3.amazonaws.com/0/16700/0605933d-32f7-2b08-f275-5e119476ffef.png)

*[ReactorKit/Examples/Counter/README.md](https://github.com/ReactorKit/ReactorKit/tree/master/Examples/Counter)*

中央にカウントを表示し、 `-` で-1、 `+` で+1とカウントを増減することができるアプリです。カウントの更新中を表すUIActivityIndicatorViewもカウントの下にあります。

```swift:CounterViewController
// Viewプロトコルに準拠すると`self.reactor`プロパティが利用可能になります。
// CounterViewControllerはStoryboardから生成されますのでStoryboardViewプロトコルに準拠しています。
final class CounterViewController: UIViewController, StoryboardView {
  @IBOutlet var decreaseButton: UIButton!
  @IBOutlet var increaseButton: UIButton!
  @IBOutlet var valueLabel: UILabel!
  @IBOutlet var activityIndicatorView: UIActivityIndicatorView!
  var disposeBag = DisposeBag()

  func bind(reactor: CounterViewReactor) {
    // Action
    increaseButton.rx.tap               // タップイベント
      .map { Reactor.Action.increase }  // タップイベントをAction.increaseに変換
      .bind(to: reactor.action)         // Actionをreactor.actionにバインド
      .disposed(by: disposeBag)

    decreaseButton.rx.tap               // タップイベント
      .map { Reactor.Action.decrease }  // タップイベントをAction.decreaseに変換
      .bind(to: reactor.action)         // Actionをreactor.actionにバインド
      .disposed(by: disposeBag)

    // State
    reactor.state.map { $0.value }      // カウントの値
      .distinctUntilChanged()           // カウントの値に変化があるか
      .map { "\($0)" }                  // カウントの値を文字列に変換
      .bind(to: valueLabel.rx.text)     // カウントの値の文字列をUILabelのtextにバインド
      .disposed(by: disposeBag)

    reactor.state.map { $0.isLoading }  // ロード中か
      .distinctUntilChanged()           // 値に変化があるか
      .bind(to: activityIndicatorView.rx.isAnimating) // ロード中かをUIActivityIndicatorViewのアニメーションにバインド
      .disposed(by: disposeBag)
  }
}
```

```swift:CounterViewReactor
final class CounterViewReactor: Reactor {
  // Viewが行うアクション
  enum Action {
    case increase
    case decrease
  }

  // Actionに対する変更内容
  enum Mutation {
    case increaseValue
    case decreaseValue
    case setLoading(Bool)
  }

  // Viewの状態(具体的な値を保持)
  struct State {
    var value: Int
    var isLoading: Bool
  }
  
  let initialState: State

  init() {
    self.initialState = State(
      value: 0, // カウントする値の初期値は0
      isLoading: false
    )
  }
  
  // ActionからMutationを生成する
  func mutate(action: Action) -> Observable<Mutation> {
    switch action {
    case .increase:
      return Observable.concat([
        Observable.just(Mutation.setLoading(true)),
        Observable.just(Mutation.increaseValue).delay(0.5, scheduler: MainScheduler.instance),
        Observable.just(Mutation.setLoading(false)),
      ])

    case .decrease:
      return Observable.concat([
        Observable.just(Mutation.setLoading(true)),
        Observable.just(Mutation.decreaseValue).delay(0.5, scheduler: MainScheduler.instance),
        Observable.just(Mutation.setLoading(false)),
      ])
    }
  }  

  // MutationからStateを更新する
  func reduce(state: State, mutation: Mutation) -> State {
    var state = state
    switch mutation {
    case .increaseValue:
      state.value += 1

    case .decreaseValue:
      state.value -= 1

    case let .setLoading(isLoading):
      state.isLoading = isLoading
    }
    return state
  }
}
```

## 実装の流れ

- 必ずしもこの流れで実装するわけではないのですが、Counterを例に実装の流れを解説します。

### 1. Stateの定義

- Viewの状態(具体的な値を保持)を表すためのStateを定義します。カウントするための値を保持する `value: Int` とロード中を表す `var isLoading: Bool` を定義します。

```swift:State
struct State {
  var value: Int
  var isLoading: Bool
}
```

### 2. Viewが行いたいAction（ロジック）を定義

- Viewから行いたいことはカウントの増減です。

```swift:Action
enum Action {
  case increase // 値の増加
  case decrease // 値の減少
}
```

### 3. Actionに対するMutation（変更内容）の定義

Actionから具体的な変更内容を定義します。

~~※ このサンプルの要件的には、Mutationの定義は省略することができます。詳しくは後述のCounterをリファクタリングを参照してください。~~ (※ v1.1.0のサンプルではMutationの内容が変更され省略不可になりました)

```swift:Mutation
enum Mutation {
  case increaseValue    // 値の増加
  case decreaseValue    // 値の減少
  case setLoading(Bool) // ロード中か
}
```

### 4. ActionからMutationを生成するロジックを実装

発行されたActionをMutationに変更します。ポイントは複数の `Observable.concat()` を使って1つのActionから複数のMutationを生成していることです。Mutation.increaseValueはdelayを使って仮想的に非同期更新しているようなイメージを持っていただくと以下の流れがわかると思います。

1. Mutation.setLoading(true)で値の更新前にロード状態をtrueにする
2. Mutation.increaseValueで値を更新する
3. Mutation.setLoading(false)で値の更新が終わったにロード状態をfalseにする

*[補足] `Observable.concat()` は複数の Observable を完了するまで待って順次 subscribe します。*

```swift:mutate
// ActionからMutationを生成する
func mutate(action: Action) -> Observable<Mutation> {
  switch action {
  case .increase:
    return Observable.concat([
      Observable.just(Mutation.setLoading(true)),
      Observable.just(Mutation.increaseValue).delay(0.5, scheduler: MainScheduler.instance),
      Observable.just(Mutation.setLoading(false)),
    ])

  case .decrease:
    return Observable.concat([
      Observable.just(Mutation.setLoading(true)),
      Observable.just(Mutation.decreaseValue).delay(0.5, scheduler: MainScheduler.instance),
      Observable.just(Mutation.setLoading(false)),
    ])
  }
}
```

### 5. MutationからStateの内容を更新するロジックを実装

発行されたMutationを元にStateのvalueを増減させます。

```swift:reduce
// MutationからStateを更新する
func reduce(state: State, mutation: Mutation) -> State {
  var state = state
  switch mutation {
  case .increaseValue:
    state.value += 1

  case .decreaseValue:
    state.value -= 1

  case let .setLoading(isLoading):
    state.isLoading = isLoading
  }
  return state
}
```

### 6. Stateの初期値を定義

中央に表示するカウントの初期値を定義します。

```swift
let initialState: State

init() {
  self.initialState = State(
    value: 0, // カウントする値の初期値は0
    isLoading: false
  )
}
```

### 7. ViewでActionの発行を実装

increaseButton/decreaseButtonのタップイベントをそれぞれのActionに変換してreactor.actionにバインドします。

```swift:bind(reactor:)
increaseButton.rx.tap               // タップイベント
  .map { Reactor.Action.increase }  // タップイベントをAction.increaseに変換
  .bind(to: reactor.action)         // Actionをreactor.actionにバインド
  .disposed(by: disposeBag)

decreaseButton.rx.tap               // タップイベント
  .map { Reactor.Action.decrease }  // タップイベントをAction.decreaseに変換
  .bind(to: reactor.action)         // Actionをreactor.actionにバインド
  .disposed(by: disposeBag) 
```

### 8. Stateの変更から具体的な各Viewを更新

- reactor.state.valueをvalueLabel.rx.textにバインドして、中央の値を表示を更新する。
- reactor.state.isLoadingをactivityIndicatorView.rx.isAnimatingにバインドして、ロード中がわかるようにUIActivityIndicatorViewを更新する。

```swift:bind(reactor:)
reactor.state.map { $0.value }     // カウントの値
  .distinctUntilChanged()          // カウントの値に変化があるか
  .map { "\($0)" }                 // カウントの値を文字列に変換
  .bind(to: valueLabel.rx.text)    // カウントの値の文字列をUILabelのtextにバインド
  .disposed(by: disposeBag)

reactor.state.map { $0.isLoading } // ロード中か
  .distinctUntilChanged()          // 値に変化があるか
  .bind(to: activityIndicatorView.rx.isAnimating) // ロード中かをUIActivityIndicatorViewのアニメーションにバインド
  .disposed(by: disposeBag)
```

# Counterをリファクタリング (v1.1.0のサンプルでは不可)

**[注意] v1.1.0のサンプルではActionとMutationが同定義ではないため以下のリファクタリングはできなくなりました。以下は[v0.4.5](https://github.com/ReactorKit/ReactorKit/tree/0.4.5/Examples/Counter)の時に有効だった内容です。**

Counterの実装を見て`Mutation`って意味ないんじゃないのかなって思った方もいると思います。
実はその通りで、このサンプルの機能的にはMutationは必要ないです。おそらくこのサンプルの目的が、シンプルな例でReactorKitの実装を紹介するということなので意図して設けられているだけだと思われます。

Mutationは、

    associatedtype Mutation = Action

となっているので、Mutationで特に行うべきロジックがない場合はActionのみを定義することが許容されています（Mutationを定義しなければActionと同じ定義になります）。

CounterからMutationを取り除くと、次のようにリファクタリングできます。

```swift:CounterViewReactor
final class CounterViewReactor: Reactor {
  // Viewが行うアクション
  enum Action {
    case increase
    case decrease
  }

  // Viewの状態(具体的な値を保持)
  struct State {
    var value: Int
  }

  let initialState = State(value: 0) // カウントする値の初期値は0
  
  // Mutation(Actionと同定義)からStateを更新する
  func reduce(state: State, mutation: Mutation) -> State {
    switch mutation {
    case .increase:
      return State(value: state.value + 1)
    case .decrease:
      return State(value: state.value - 1)
    }
  }
}
```

# まとめ

まずはReactorKitの概要ということでシンプルなCounterを例に取り上げました。Viewに必要な数値のカウントアップ/ダウン機能(ビジネスロジック)と現在のカウント数の保持をViewから切り離し、それらをReactorに移譲することができました。正直この規模だとまだメリットは感じられないと思いますが、アプリがより複雑化したときにReactorKitが活きてきます。

個人的には今一番好きなアーキテクチャがReactorKitです。

- アーキテクチャを構築するためのフレームワークなので、正しいアーキテクチャを構築するための学習コストが抑えられる
- 単方向ストリームがすでに構築されているので、MVVMでいうとViewとViewModelとの双方向バインディングの複雑さを軽減できる
- 各責務が明瞭
- 他人のコードを読んでも把握が楽
- 最少は1つ以上のViewに対して1つのReactorを設けるだけなので、一部分だけの導入も可能。1つのアプリが単一のアーキテクチャに縛られる必要はないです😉

何よりも設計思想が好きですね。アーキテクチャの学習/導入/運用コストを大きく上回るだけのメリットを感じています。

次回はさらにReactorKitを掘り下げて見たいと思います。
→ [ReactorKit(Flux + Reactive Programming)を学ぶ2 基礎編](http://qiita.com/yusuga/items/cf08cf172c92364c1e14)

---

*※ 本文中の画像は[ReactorKit](https://github.com/ReactorKit/ReactorKit)から引用*