🌾

[Swift] [Combine] Publisher を flatMap() 内に隠蔽して直接 subscribe するのを避ける方法

2022/02/22に公開

はじめに

以下の記事にもあるように、『Failure となる可能性がある Publisher を直接 subscribe している場合、一度でも Failure が発生すると、その時点で Completion となり、Output を受け付けなくなる』という挙動を示します。

その回避方法として、記事内では flatMap() 内での tryMap() -> catch -> Empty の合わせ技 を紹介しているのですが、そもそも外側にある Publisher を flatMap() 内に隠蔽する方法について、いくつかパターンがあるので、それを紹介する記事になります。


以下は共通のコードになります。

前提
import Combine
import Foundation

var cancellables: Set<AnyCancellable> = []

let numPublisher = PassthroughSubject<Int, Never>()

方法1: Just() を使う ← オススメ

以下になります。

numPublisher
    .flatMap {
        Just($0)
            .eraseToAnyPublisher()
    }
    .sink { print("\($0)") }
    .store(in: &cancellables)

言われてみれば、それはそうなのですが、Just() を使えば一発ですね。

これが一番シンプルだと思います。

方法2: map() による配列変換 -> Array.publisher を使う

以下になります。

numPublisher
    .map { [$0] }
    .flatMap {
        $0.publisher
    }
    .sink { print("\($0)") }
    .store(in: &cancellables)

配列であれば、.publisher によるアクセスで、Publisher 変換できるので、それを利用した形になります。

方法3: collect(1) による配列変換 -> Array.publisher を使う

以下になります。

numPublisher
    .collect(1)
    .flatMap {
        $0.publisher
    }
    .sink { print("\($0)") }
    .store(in: &cancellables)

方法2 とやっていることは同じです。

ちょっと玄人感があります。

結論

  • Publisher を flatMap() 内に隠蔽して直接 subscribe するのを避けるなら、Just() を使おう

以上になります。

GitHubで編集を提案

Discussion