出错后如何继续订阅发布者?
How to continue subscribing to publisher after error?
我正在尝试设置一个将发布一组整数的发布者,但有时可能会失败。它有点做作,但希望能说明原理。示例如下。
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)
}
}
然后我订阅使用:
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([=11=])
})
n.start(max: 5)
这是因为它用 -1 替换了错误,但我想继续接收值。有谁知道这是否可能?
阅读并环顾四周后,似乎 flatMap 可能是可行的方法,但我无法确定在闭包中使用哪个发布者?非常感谢任何帮助。
我认为您错误地认为 PassthroughSubject
可以在发布失败后发布更多输出。这不可以。在您调用 p.send(completion: ...)
之后,任何对 p.send(...)
的调用都将被忽略。此外,如果您在调用 p.send(completion: ...)
后订阅 p
,p
将立即完成新订阅并且不会发送任何输出。
因此,如果您想在之后发送更多值,则不能将错误作为 .failure
发送。相反,将发布商的 Output
类型更改为 Result<Int, NumberError>
并将其 Failure
类型更改为 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
:
let n = Numbers()
let c = n.p
.map({
switch [=11=] {
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([=11=])
})
n.start(max: 5)
输出:
1
2
-1
4
5
Finished
我正在尝试设置一个将发布一组整数的发布者,但有时可能会失败。它有点做作,但希望能说明原理。示例如下。
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)
}
}
然后我订阅使用:
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([=11=])
})
n.start(max: 5)
这是因为它用 -1 替换了错误,但我想继续接收值。有谁知道这是否可能? 阅读并环顾四周后,似乎 flatMap 可能是可行的方法,但我无法确定在闭包中使用哪个发布者?非常感谢任何帮助。
我认为您错误地认为 PassthroughSubject
可以在发布失败后发布更多输出。这不可以。在您调用 p.send(completion: ...)
之后,任何对 p.send(...)
的调用都将被忽略。此外,如果您在调用 p.send(completion: ...)
后订阅 p
,p
将立即完成新订阅并且不会发送任何输出。
因此,如果您想在之后发送更多值,则不能将错误作为 .failure
发送。相反,将发布商的 Output
类型更改为 Result<Int, NumberError>
并将其 Failure
类型更改为 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
:
let n = Numbers()
let c = n.p
.map({
switch [=11=] {
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([=11=])
})
n.start(max: 5)
输出:
1
2
-1
4
5
Finished