错误后如何继续订阅发布者? [英] How to continue subscribing to publisher after error?
问题描述
我正在尝试建立一个发布者,该发布者将发布一组整数,并且有时可能会失败.稍作设计,但希望能说明原理.下面的示例.
I am trying to set up a publisher that will publish a set of integers and at some point may fail. It's slightly contrived but hopefully illustrates principle. Example below.
enum NumberError: Int, Error {
case isFatal, canContinue
}
struct Numbers {
let p = PassthroughSubject<Int, NumberError>()
func start(max: Int) {
let errorI = Int.random(in: 1...max)
for i in (1...max) {
if errorI == i {
p.send(completion: .failure(NumberError.canContinue))
} else {
p.send(i)
}
}
p.send(completion: .finished)
}
}
然后我使用以下方式订阅:
I then subscribe using:
let n = Numbers()
let c = n.p
.catch {_ in return Just(-1)}
.sink(receiveCompletion: {result in
switch result {
case .failure:
print("Error")
case .finished:
print("Finished")
}
}, receiveValue: {
print($0)
})
n.start(max: 5)
此方法的工作原理是将错误替换为-1,但我想继续接收值.有人知道这是否可能吗?阅读并环顾四周,似乎可以选择flatMap,但是我无法确定要在闭包中使用哪个发布者?任何帮助表示赞赏.
This works in that it replaces errors with -1 but I would then like to continue receiving values. Does anyone know if this is possible? Having read and looked around it seems that flatMap may be the way to go but I can't work out what publisher to use in the closure? Any help much appreciated.
推荐答案
我认为您错误地认为 PassthroughSubject
可以在发布故障后发布更多输出.这不可以.调用 p.send(completion:...)
后,对 p.send(...)
的所有调用都将被忽略.此外,如果在调用 p.send(completion:...)
之后订阅了 p
, p
将立即完成新的订阅,并且不发送任何输出.
I think you have an incorrect belief that a PassthroughSubject
can publish more outputs after publishing a failure. It cannot. After you call p.send(completion: ...)
, any calls to p.send(...)
will be ignored. Furthermore, if you subscribe to p
after you call p.send(completion: ...)
, p
will immediately complete the new subscription and not send any outputs.
因此,如果您想在以后发送更多值,则无法将错误作为 .failure
发送.而是将发布者的 Output
类型更改为 Result< Int,NumberError>
,将其 Failure
类型更改为 Never
:
So you can't send your error as .failure
if you want to send more values after. Instead, change your publisher's Output
type to Result<Int, NumberError>
and its Failure
type to Never
:
import Combine
enum NumberError: Int, Error {
case isFatal, canContinue
}
struct Numbers {
let p = PassthroughSubject<Result<Int, NumberError>, Never>()
func start(max: Int) {
let bad = (max + 1) / 2
for i in (1...max) {
if bad == i {
p.send(.failure(NumberError.canContinue))
} else {
p.send(.success(i))
}
}
p.send(completion: .finished)
}
}
但是现在您不能使用 catch
来处理错误,因为它不会作为失败而通过.相反,您可以使用 map
:
But now you can't use catch
to handle the error, because it's not coming through as a failure. Instead, you can use map
:
let n = Numbers()
let c = n.p
.map({
switch $0 {
case .success(let i): return i
case .failure(_): return -1
}
})
.sink(receiveCompletion: {result in
switch result {
case .failure:
print("Error")
case .finished:
print("Finished")
}
}, receiveValue: {
print($0)
})
n.start(max: 5)
输出:
1
2
-1
4
5
Finished
这篇关于错误后如何继续订阅发布者?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!