🦁

SwiftUIでFluxのiOSアプリをつくってみた

2021/09/28に公開

前回の続きです。

前回の記事

https://zenn.dev/st43/articles/faf32d5f69e96b

参考書

アーキテクチャーに関する知識は、こちら↓を参照しています。
以下の文中で「参考書」と出てきたらこの本のことを指します。

https://peaks.cc/books/iOS_architecture

環境

  • Xcode: 13.0
  • iOS: 15.0
  • Swift: 5.5

Fluxとは

  • 2014年にFacebookから発表されたアーキテクチャー
  • データフローが単一方向に流れることを目指したアーキテクチャー
  • Action → Dispatcher → Store → Viewというデータフローをつくる
  • ViewはStoreを監視していて、Storeが更新された際に描画処理を行う
  • View→Storeという直接更新はできず、必ずActionを生成する
  • Actionはキー名に近いものであり、この生成のためにActionCreatorというクラスをつくる
  • 公式のコンセプトはここ↓
  • https://github.com/facebook/flux/tree/3.1.1/examples/flux-concepts

  • スケールしそうな感じはする

Swiftで実装するとき

  • FluxはWebのアーキテクチャーなので、iOSで使うときは応用になる
  • Dispatcherはシングルトンになるのが、個人的にはちょっと嫌なところ
  • ActionCreatorがAPI接続担当するんだけど、これ地味に役割大きくない? と思った
  • イニシャルするタイミングが難しいなと思ったけど、サンプルだとStoreとActionCreatorはAppDelegateでやっていた

実装してみた

実装しました。

https://github.com/0si43/iOS-architecture-training/tree/Flux

さすがにMVxアーキテクチャーと比べるとわかりづらくなりましたが、構造としてはこうです。

IMG_5BFEC7AA4AAF-1.jpeg

参考書ではView - Store間をNotificationCenterで監視していましたが、お馴染みのCombineを使いました。
元々のViewだとエラーが返ってきたときにエラーメッセージを出してたんですが、Fluxだとエラーを伝播させるのがめんどくさかったので、バッサリやめました。
エラーはActionCreatorでコンソールに出すだけにしています。

Dispatcher/UserSearchStore/RepositoryStoreはシングルトンになっています。
また、Dispatcher/Store(親)は、そのまま使えそうだったので、サンプルを丸パクリしました。

https://github.com/peaks-cc/iOS_architecture_samplecode/tree/master/08/FluxExample/FluxExample

ユーザーからのデータフローはこのようになります。

一方向ですね。

Viewがレンダリングするときに必ず実行される書き方が欲しい

RepositoryViewをFlux化したとき、二回目以降のサーバー通信が走らないことに気づきました。
前回の表示結果をそのまま表示してしまいます。
これはViewの仕様で、ローディング画面のProgressViewに.onAppearをつけて、サーバー通信の発火を行なっていて、
Flux化するとStoreの中のisLodingの更新まで行かないので、永遠に前回の結果を表示し続けることになりました。

ちょっと悩んで、画面遷移のところに.onAppearをつけまして、ここで「startRepositoriesLoding」というアクションを呼ばせることにしました。

List(userSearchStore.users) { user in
    NavigationLink(destination: RepositoryView(repositoryUrlString: user.reposUrl)
                    .onAppear {
                        actionCreator.startRepositoriesLoding()
                    }) {
        UserRow(user: user)
    }
}

だいぶイマイチではあります。
Viewがレンダリングするときに必ず実行される書き方があるといいんですけど。

まとめ

というわけで、Fluxでした。
個人的にはあんまり好きじゃないアーキテクチャーでした。
僕自身が「直感的だけど効果が高い」のが好みなので、Fluxはなんというか直感的ではないと感じました。
自分から積極的に使おうとは思わないですかね〜

ただユーザー検索を実装して、リポジトリ一覧表示の方を追加しているときに気づいたんですが、
Action/Dispatcher/Storeの仕組みをつくってしまうと、あとは何も考えずに追加できるので、
複数人の大規模開発だと、気持ちよくスケールできそうな予感はしました。
またStoreのコールバックで、全Actionに対して処理を書くところは明確でいいなと思いました。
何をやらせたくて、何に興味がないのかがパッとわかるので、リファクタリングしやすそうです。

DispatcherやStoreがシングルトンになっちゃうところとか、結局実装の都合でイマイチな粒度のActionをつくっちゃったりとかがデメリットかなと思いました。
特にスケールしたときに、Actionは爆発的な数になりそうなので、そこでごちゃついちゃいそうだなとも思いました。

Discussion