【Swift/Combine】combineLatestで複数条件を監視する方法!mergeやzipとの違い

この記事からわかること
- SwiftのCombineフレームワークの使い方
- combineLatestメソッドとは?
- 複数のpublisherを1つにまとめて監視する方法
- mergeやzipとの違いや使い分け
index
[open]
\ アプリをリリースしました /
環境
- Xcode:15.0.1
- iOS:17.1
- Swift:5.9
- macOS:Sonoma 14.1
combineLatestメソッドの使い方
combineLatest
は複数のpublisherをまとめて1つのpublisherにして管理することができるメソッドです。例としてバリデーションロジックを実装する時など「全てがtrueの場合のみ処理を実装」する場合で考えてみます。
combineLatest
メソッドは1つのpublisherから呼び出し、引数に一緒に観測させたいpublisherを渡します。まとめた後のオペレーターからはタプルで流れてくるそれぞれの値を参照することが可能ですが、map
などを使用して1つの値を流すように変換すると見通しが良くなります。
combineLatest
メソッドでまとめると全てのpublisherから値が流れてこないと処理が走りません。以下のようにsubjectC
だけsend
メソッドが送られていない状態の場合はその後のオペレーターなどは動作しなくなります。
全ての値が一度でも流れていれば、それ以降はいずれかの値が流れてくるたびに動作します。
publisherのデータ型はバラバラでもOK
publisher
が保持するデータ型が異なっていても正常に動作します。
まとめられる最大個数
combineLatest
は引数の個数違いで複数定義されていますが、用意されているのは最大3個までのようです。
3個以上をまとめたい場合はcombineLatest
を再度呼び出せばsink
の引数ではタプルになってしまいますが、結合させることができます。
エラー型が異なる場合は連結できない
連結したいpublisher
のエラー型が異なる場合はコンパイルエラーが発生します。
そのためsetFailureType
やmapError
などを使用して適切にエラーの型を合わせてあげる必要があります。
エラー型の統一は後述するmerge
やzip
、flatMap
などでも同じです。
並列実行
時間のかかるpublisher
だと把握しやすいですがcombineLatest
で連結させると並列処理でpublisherを実行することが可能です。
そのためslowPublisher(3)
とslowPublisher(5)
は同時にカウントが始まるので出力は以下のようになります。
mergeやzipとの違いと使い分け
似たようなpublisherをまとめるメソッドにmerge
やzip
があります。それぞれの違いは以下の通りです。
- combineLatest:最新の値を使って結合。最低でも1回は値が送信されるまで結合されない。
- merge:複数のpublisherからのイベントを単一のpublisherに順次結合
- zip:対応する位置の値をペアにして出力。最小のpublisherが完了すると結合
mergeメソッド
mergeメソッドは複数のpublisherからのイベントを単一のpublisherに順次結合するメソッドです。実行してみるとわかりますが、複数のpublisherをmergeしても流れてくる値は1つのみです。つまり両方のイベントが発火するタイミングで同じpublisherから値が観測することができるので全てのpublisherの値が揃うのを待つわけではありません。
そのため出力は以下のようになります。
Output型は統一する
merge
メソッドはOutput
が1つにまとめられてしまうのでOutput
型を統一する必要があります。異なるOutput
型でmerge
しようとするとNo exact matches in call to instance method 'merge'
というコンパイルエラーが発生するのでmap
などを使用してOutput
型を変換する必要があります。
zipメソッド
zip
メソッドは複数のpublisherに対応する位置の値をペアにして出力します。値が流れるのはzip
でまとめている値が全て揃った時です。
値が一度流れると再度全ての値が揃うまで動作することはありません。例えば以下のようなイベントの流れ方をした場合は「11行目の3つの値が揃ったタイミング」で値が流れます。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。