skip to content
私的歌詞倉庫

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に変換する方法が分かりませんでしたが、ようやくわかったのでその方法について紹介します。

今回使ったツールたちのバージョンです。

ツールバージョン
Swift5.9
Xcode15.3 (15E204a)
TCA1.9.2

変換

こんな感じでEffect.publisherを使って変換するようです。

import Combine
import ComposableArchitecture
@Reducer
public 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はバージョンアップでの変更が激しいので、昔の解説サイトなどのサンプルコードがそのままでは動かないケースもあったりして大変だなと思いました。

やはり信じられるのは、公式ドキュメントのみ…!

参考文献