はじめに
本日は最近JavaScript界では浸透してきているRedux
についてSwiftを通して勉強していきたいと思います。
Redux
に関する日本語の記事はそれなりにあるもののSwift版ライブラリであるReSwift
に関する日本語の記事は少ないため、筆者が少しでも記事を増やせたら良いなという思いがあります。
と言いつつも、いきなり有効性の高い有良記事を書くことはハードルが高いため、簡単な勉強から始めて行く次第です。
ReSwiftとは
ReSwift
とはRedux
のSwift版ライブラリです。
GitHub: ReSwift/ReSwiftが公式ページとなります。
上記公式ページのイントロをざっくり訳すと…
(意味が間違っていたらごめんなさい…)
ReSwiftはSwiftでReduxライクな一方向のデータフローアーキテクチャを実装したものです。ReSwiftを使うことで、次の3つの関係性でアプリを構成することを手助けします。
- State : 全てのアプリの状態を管理します。複雑な状態の管理やデバッグのし易さを手助けするなど、メリットは数多くあります。
- Views : 状態変化したときにViewを更新します。状態に対してシンプルなビジュアルを実現します。
- State Changes :
actions
を通した状態変化の実行のみを担当します。actions
は状態変化を表現する小さなモジュールを指します。限られた状態変化を担うため、大人数で開発する際にアプリを簡単に理解することができるメリットがあります。
また、ReSwiftは下記の3つの原則に従って構成されます。
- The Store : アプリの状態(State)を保持するアプリ内で唯一の存在です。StoreにActionsが発送されることによってのみ状態(State)は変化します。状態(State)が変化したら必ず、Storeが全てのオブザーバに通知します。
- Actions : アプリの状態(State)がどんな変化なのかを宣言します。Storeによって消費され、Reducerに渡されます。Reducerは各Actionで引き起こされる異なる状態変化を実装することによってActionを扱います。
- Reducers : 現在のActionとStateに基いて、新しいStateを生成する純粋な関数を提供します。
というように、何となく、この辺りを理解すれば良さそうですね。
まずは、公式ページに載っている最も簡単な『Counterサンプルアプリ』から上記の内容を直にコードで理解していきたいと思います。
CounterサンプルアプリからReSwiftを理解しよう
公式ページのREADMEにはCounterExampleが紹介されています。
公開されているサンプルアプリの中で最も簡単なサンプルなはずなので、これを見ていきたいと思います。
最終的なフォルダ構成は下記になります。
(関係のないファイルは除いています。)
1 2 3 4 5 6 7 8 9 10 |
|
では早速、1つずつ見ていきましょう。
ReSwiftをCocoaPodsでインストール
例によってCocoaPodsでインストールします。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
これでpod install
すればOKです。
State
準備が整ったところでコードを具体的に見ていきましょう。
まずはAppState.swift
を見ていきます。
1 2 3 4 5 6 7 |
|
今回のアプリは単純なカウントアップアプリなので、上記ではAppState
の1つのプロパティとして カウントの状態(counter) を定義しています。
Action
続いてCounterActions.swift
を見ていきます。
1 2 3 4 5 6 |
|
カウントアップの動作には 『増加(Increase)』 と 『減少(Decrease)』 の2つがあるため、それぞれのActionを定義します。
ここで注意したいのはActionは関数(func
)ではなく構造体(struct
)であるということです。
先に述べたようにActionは状態の宣言であり、Reducerに渡されて、処理を判別するために利用されるからです。
Reducer
そして、CounterReducers.swift
を見ていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
先に述べましたが、Reducerは引数として渡されたStateとActionの2つから新規のStateを返却します。
重要なのは、 新規のStateを返却する ということです。
これはvar state = state ?? AppState()
を見るとわかるかと思います。
既にstate
オブジェクトがある場合は値渡しで新規AppState
型に内容を格納しています。
もし、state
オブジェクトがなければ、初期化して作成しています。
そしてswitch
文で各Actionごとに最適な処理を実行しています。
(今回の場合は『Increase』と『Decrease』)
Store
モジュールの作成が完了したので、実装していきます。
先に述べたようにStore
はアプリの状態(State)を保持するアプリ内で 唯一の存在 です。
よって、AppDelegate.swift
で次のように定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
上記ではStore
型のmainStore
を定義しています。
ReducerとしてCounterReducer
を定義しています。
Stateは初期値nil
として定義しています。
View層への実装
最後にユーザの操作が走った際の処理の実装について見ていきます。
状態変化の監視開始/終了を下記で実施します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
続いて、ユーザ操作からのReducerへのAction発送部分です。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
- 『増加』ボタンタップ時にStoreが『CounterActionIncreaseというAction』をReducerへdispatch(発送)します。
- 『減少』ボタンタップ時にStoreが『CounterActionDecreaseというAction』をReducerへdispatch(発送)します。
そして、新しいStateが返却された際に実行すべき処理を書くためにStoreSubscriber
プロトコルにnewState
メソッドが定義されています。
よって、
1 2 3 4 5 6 7 8 9 10 11 12 |
|
のように実装することでnewState
メソッド内で任意の処理を書くことができます。
まとめ
さて、如何でしたでしょうか?
今回は公式の最も簡単なサンプルについて見ていきましたが、少々ReSwiftの扱い方が見えてきた気がします。
また、ReSwiftが有能であるが故にReduxであればもっと自分で書かなければいけなさそうなところもカバーしてくれているように見えました。
実践での活用なRxSwift同様にいろいろなリスク管理的な意味で難しいのかもしれませんが、もっとReSwiftを理解することで想定を上回るメリットを示し、実践で利用できるかもしれません。
そんなことを夢見ながら今後は、別の公式サンプルを見つつ理解を深めていきたい思います。
と言ったところで本日はここまで。