Combine sink:忽略receiveValue,只需要completion
Combine sink: ignore receiveValue, only completion is needed
考虑以下代码:
CurrentValueSubject<Void, Error>(())
.eraseToAnyPublisher()
.sink { completion in
switch completion {
case .failure(let error):
print(error)
print("FAILURE")
case .finished:
print("SUCCESS")
}
} receiveValue: { value in
// this should be ignored
}
只需查看 CurrentValueSubject
初始值设定项,很明显该值不需要/无关紧要。
我正在使用这个特定的发布者发出异步网络请求,该请求可能通过也可能失败。
由于我对这个发布者返回的值不感兴趣(有none),我怎样才能摆脱receiveValue
闭包?
理想情况下,调用站点代码应如下所示:
CurrentValueSubject<Void, Error>(())
.eraseToAnyPublisher()
.sink { completion in
switch completion {
case .failure(let error):
print(error)
print("FAILURE")
case .finished:
print("SUCCESS ")
}
}
也有可能我应该使用不同于 AnyPublisher
的东西,所以如果 API 更符合目的,请随意提出/重写它。
我能找到的最接近的解决方案是 ignoreOutput,但它仍然是 returns 一个值。
CurrentValueSubject
似乎是一个令人困惑的选择,因为当您第一次订阅它时,它会发送一个初始值(Void
)。
您可以使用 Future
来减少歧义,它会在完成后发送唯一的值。
为了避免必须接收您不关心的值,您可以翻转情况并使用 Result<Void, Error>
的输出类型和 Never
的失败类型。当处理你的网络请求时,你可以用 .failure(error)
或 .success(())
履行承诺,并在 sink:
中处理它
let pub = Future<Result<Void, Error>, Never> {
promise in
// Do something asynchronous
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
promise(.success(.success(())))
//or
//promise(.success(.failure(error)))
}
}.eraseToAnyPublisher()
// somewhere else...
pub.sink {
switch [=10=] {
case .failure(let error):
print("Whoops \(error)")
case .success:
print("Yay")
}
}
您正在将链条一端的丑陋代码换成另一端的丑陋代码,但如果它隐藏在 AnyPublisher
后面并且您关心正确使用,这似乎是可行的方法.消费者可以通过查看输出和错误类型准确地看到预期的结果,而不必在单独的闭包中处理它们。
您只需完成即可声明另一个接收器:
extension CurrentValueSubject where Output == Void {
func sink(receiveCompletion: @escaping ((Subscribers.Completion<Failure>) -> Void)) -> AnyCancellable {
sink(receiveCompletion: receiveCompletion, receiveValue: {})
}
}
考虑以下代码:
CurrentValueSubject<Void, Error>(())
.eraseToAnyPublisher()
.sink { completion in
switch completion {
case .failure(let error):
print(error)
print("FAILURE")
case .finished:
print("SUCCESS")
}
} receiveValue: { value in
// this should be ignored
}
只需查看 CurrentValueSubject
初始值设定项,很明显该值不需要/无关紧要。
我正在使用这个特定的发布者发出异步网络请求,该请求可能通过也可能失败。
由于我对这个发布者返回的值不感兴趣(有none),我怎样才能摆脱receiveValue
闭包?
理想情况下,调用站点代码应如下所示:
CurrentValueSubject<Void, Error>(())
.eraseToAnyPublisher()
.sink { completion in
switch completion {
case .failure(let error):
print(error)
print("FAILURE")
case .finished:
print("SUCCESS ")
}
}
也有可能我应该使用不同于 AnyPublisher
的东西,所以如果 API 更符合目的,请随意提出/重写它。
我能找到的最接近的解决方案是 ignoreOutput,但它仍然是 returns 一个值。
CurrentValueSubject
似乎是一个令人困惑的选择,因为当您第一次订阅它时,它会发送一个初始值(Void
)。
您可以使用 Future
来减少歧义,它会在完成后发送唯一的值。
为了避免必须接收您不关心的值,您可以翻转情况并使用 Result<Void, Error>
的输出类型和 Never
的失败类型。当处理你的网络请求时,你可以用 .failure(error)
或 .success(())
履行承诺,并在 sink:
let pub = Future<Result<Void, Error>, Never> {
promise in
// Do something asynchronous
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
promise(.success(.success(())))
//or
//promise(.success(.failure(error)))
}
}.eraseToAnyPublisher()
// somewhere else...
pub.sink {
switch [=10=] {
case .failure(let error):
print("Whoops \(error)")
case .success:
print("Yay")
}
}
您正在将链条一端的丑陋代码换成另一端的丑陋代码,但如果它隐藏在 AnyPublisher
后面并且您关心正确使用,这似乎是可行的方法.消费者可以通过查看输出和错误类型准确地看到预期的结果,而不必在单独的闭包中处理它们。
您只需完成即可声明另一个接收器:
extension CurrentValueSubject where Output == Void {
func sink(receiveCompletion: @escaping ((Subscribers.Completion<Failure>) -> Void)) -> AnyCancellable {
sink(receiveCompletion: receiveCompletion, receiveValue: {})
}
}