Combineを使用する際に勉強不足が故にハマってしまったので、備忘録として残します。
問題
関数から返されるFuture型の変数にて
func handleEvents(
receiveSubscription: ((Subscription) -> Void)? = nil,
receiveOutput: ((Output) -> Void)? = nil,
receiveCompletion: ((Subscribers.Completion<Failure>) -> Void)? = nil,
receiveCancel: (() -> Void)? = nil,
receiveRequest: ((Subscribers.Demand) -> Void)? = nil
) -> Publishers.HandleEvents<Future<Output, Failure>>
をコールしてクロージャ内で処理を行いたいが、クロージャが実行されない。
解決方法
func sink(
receiveCompletion: @escaping ((Subscribers.Completion<Failure>) -> Void),
receiveValue: @escaping ((Output) -> Void)
) -> AnyCancellable
上記のsinkをコールするなりして、サブスクライバーを接続する必要がある。
原因
当初は以下のコードを実装し、promise(.success(()))が実行されたタイミングでhanleEventsによって設定したクロージャがコールされると思った。
が、コールされない。
// Playgroundにて実行
import Combine
import Foundation
struct APIError: Error {
var description: String
}
func delay() -> Future<Void, Error> {
return Future<Void, Error>{ promise in
print("実行されます")
Thread.sleep(forTimeInterval: 2.0)
promise(.success(()))
return
}
}
func executionDelay() -> AnyPublisher<Void, Error>{
print("実行します")
return delay()
.handleEvents(receiveSubscription: {_ in
print("Subscription")
}, receiveOutput: { _ in
print("Output")
}, receiveCompletion: { _ in
print("Completion")
}, receiveCancel: {
print("Cancel")
}, receiveRequest: {_ in
print("Request")
})
.eraseToAnyPublisher()
}
// 処理を実行
executionDelay()
handleEventsのリファレンスを読むと、「Performs the specified closures when publisher events occur.」とあり、パブリッシャーイベントが発生した時にクロージャが実行されるとのこと。
しかし、よくよく考えると、サブスクライバーに接続されていないことに気づいた。
sinkメソッドをコールしてサブスクライバーを接続する必要がある。
改善したコードが以下のもの。
import Combine
import Foundation
func delay() -> Future<Void, Error> {
return Future<Void, Error>{ promise in
print("実行されます")
Thread.sleep(forTimeInterval: 2.0)
promise(.success(()))
return
}
}
func executionDelay() -> AnyPublisher<Void, Error>{
print("実行します")
return delay()
.handleEvents(receiveSubscription: {_ in
print("Subscription")
}, receiveOutput: { _ in
print("Output")
}, receiveCompletion: { _ in
print("Completion")
}, receiveCancel: {
print("Cancel")
}, receiveRequest: {_ in
print("Request")
})
.eraseToAnyPublisher()
}
// 処理を実行
executionDelay()
.sink(receiveCompletion: {completion in
print("receiveCompletion")
switch completion {
case .failure(let error):
print("失敗:\(error)")
default:
print("成功")
}
}, receiveValue: { _ in
print("receiveValue")
})