web-dev-qa-db-ja.com

Swiftパブリッシャーと完了ハンドラーを組み合わせて、いつキャンセルするか

一般的に、パブリッシャーはクロージャーよりも強力ですが、具体的な例を尋ねて説明したいと思います。

func getNotificationSettingsPublisher() -> AnyPublisher<UNNotificationSettings, Never> {
   let notificationSettingsFuture = Future<UNNotificationSettings, Never> { (promise) in
      UNUserNotificationCenter.current().getNotificationSettings { (settings) in
         promise(.success(settings))
      }
   }
   return notificationSettingsFuture.eraseToAnyPublisher()
}

これはFutureパブリッシャーの有効な例であり、完了ハンドラーを使用する代わりにここで使用できると思います。それで何かをしましょう:

func test() {
    getNotificationSettingsPublisher().sink { (notificationSettings) in
       // Do something here        
    }
}

これは機能しますが、sink(AnyCancellable)の結果は未使用であることがわかります。したがって、値を取得しようとするたびに、キャンセル可能な値を格納するか、値を取得するまでそれを割り当てる必要があります。

SinkOnceのようなものやキャンセル可能なものの自動破棄はありますか?キャンセルされた方へのタスクが不要な場合があります。しかし、私はこれを行うことができました:

func test() {
   self.cancellable = getNotificationSettingsPublisher().sink { [weak self] (notificationSettings) in
      self?.cancellable?.cancel()
      self?.cancellable = nil
   }
}

値を受け取ったら、サブスクリプションをキャンセルします。 (私は私が推測する流しの完全な閉鎖で同じことをすることができました)。

そうするための正しい方法は何ですか?なぜなら、私がクロージャーを使用する場合、それは関数が呼び出される回数だけ呼び出され、それが1回だけ呼び出される場合は、何もキャンセルする必要がないからです。

通常の完了ハンドラーをCombineで置き換えることができると思いますか?その場合、1つの値を受け取ってキャンセルする方法をどのように処理しますか?

最後に重要なことですが、完了が呼び出されますが、サブスクリプションをキャンセルする必要がありますか?少なくともキャンセル可能なものを更新してnilに設定する必要がありますか?サブスクリプションをセットに格納するのは長期実行サブスクリプション用だと思いますが、単一値サブスクリプションはどうですか?

ありがとう

2
Janosch Hübner

.sink演算子を使用する代わりに、Sinkサブスクライバーを直接使用できます。そうすれば、保存する必要があるAnyCancellableを受け取ることができません。パブリッシャーがサブスクリプションを完了すると、Combineはすべてをクリーンアップします。

func test() {
    getNotificationSettingsPublisher()
        .subscribe(Subscribers.Sink(
            receiveCompletion: { _ in },
            receiveValue: ({
                print("value: \($0)")
            })
        ))
}
2
rob mayoff