Combineを使用する際にハマってしまったので、備忘録として残します。
問題
Futureのインスタンスにsinkしてクロージャ(サブスクライバ)を設定し、非同期処理が完了した際にsinkにて設定したクロージャの処理を行いたいのだが、完了する前にSubscribeがキャンセルされてしまう。
func start() {
Future<Void, Error>{ promise in
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0){
promise(.success(()))
}
}
.handleEvents(receiveSubscription: { _ in
print("receiveSubscription")
}, receiveOutput: {
print("receiveOutput")
}, receiveCompletion: { _ in
print("receiveCompletion")
}, receiveCancel: {
print("receiveCancel")
}, receiveRequest: { _ in
print("receiveRequest")
})
// クロージャが実行されない
.sink(receiveCompletion: { completion in
print("completion:\(completion)")
}, receiveValue: {
})
}
デバッグコンソール
receiveSubscription
receiveRequest
receiveCancel
解決方法
sinkメソッドの返り値を変数に保持するか、storeメソッドを使用して保持する必要がある。
func start() {
cancellable = Future<Void, Error>{ promise in
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0){
promise(.success(()))
}
}
.handleEvents(receiveSubscription: { _ in
print("receiveSubscription")
}, receiveOutput: {
print("receiveoutput")
}, receiveCompletion: { _ in
print("receiveCompletion")
}, receiveCancel: {
print("receiveCancel")
}, receiveRequest: { _ in
print("receiveRequest")
})
.sink(receiveCompletion: { completion in
print("completion:\(completion)")
}, receiveValue: {
})
}
デバッグコンソール
receiveSubscription
receiveRequest
receiveoutput
receiveCompletion
completion:finished
原因
Future内に実装した処理が完了(promise()がコールされる)前にsinkから返却されたAnyCancellableが破棄されてしまうとキャンセルされてしまうみたい。
公式のリファレンスを読むと「Return Value」の部分にひっそりと書かれていた。