The Composable ArchitectureのReducerでPublisherをEffectに変換
/ 4 min read
Updated:Table of Contents
はじめに
最近macのアプリをThe Composable Architecture(TCA)を使って開発しています。
ただ全部をTCAでやるのではなく、ロジック部分に関してはRepositoryパターンでCombineのみを使って書いています。
UseCase層の返り値でAnyPublisher<[String]?, Never>に返すメソッドを実装したのですが、これをうまくTCAのreduceメソッド内でEffectに変換する方法が分かりませんでしたが、ようやくわかったのでその方法について紹介します。
今回使ったツールたちのバージョンです。
| ツール | バージョン |
|---|---|
| Swift | 5.9 |
| Xcode | 15.3 (15E204a) |
| TCA | 1.9.2 |
変換
こんな感じでEffect.publisherを使って変換するようです。
import Combineimport ComposableArchitecture
@Reducerpublic struct RaelizeIMKReducer {
/// UI state @ObservableState public struct State: Equatable { var hoge: [String] = [] }
/// User action public enum Action { case hoge0(String) case hoge1([String]?) }
public func reduce(into state: inout State, action: Action) -> Effect<Action> { switch action { case .hoge0(let string): return .publisher({ hogePublisher(string) .map({ Action.hoge1($0) }) }) case .hoge1(let strings): state.hoge = strings return .none default: return .none } }}
func hogePublisher(string: String) -> AnyPublisher<[String]?, Never> { // 適当な返り値…}参考にしたサイトによっては、eraseToEffect() のように変換しているのもあったのですが、最新のバージョン(1.9.2)では使えなさそうでした。他にもEffect<[String]?, Never>みたいに包んでいるのものもありましたが、これも古い書き方っぽそうでした。
色々探して、Effect.publihserがあるよとIssueに書いてあったので気づきました。
ビジネスロジック部分には、できるだけTCAなどの標準ライブラリ以外を入れたくなかったので、うまく解決できて良かったです。
一応、自分が実際に書いたコードはこちらのcommitになります。
ちなみに、reduceメソッドを使っているのは、今作っているアプリにはUIがないためこのような感じにしています。
終わりに
TCAでEffect.publihserの使い方について書きました。
concurrencyのサンプルはあったのですが、Combineのサンプルがなかった(多分)ので手こずりました。
他にもTCAはバージョンアップでの変更が激しいので、昔の解説サイトなどのサンプルコードがそのままでは動かないケースもあったりして大変だなと思いました。
やはり信じられるのは、公式ドキュメントのみ…!