为什么Combine的receive(on :)运算符会误入错误? [英] Why does Combine's receive(on:) operator swallow errors?
问题描述
以下管道:
enum MyError: Error {
case oops
}
let cancel = Fail<Int, Error>(error: MyError.oops)
.print("1>")
.print("2>")
.sink(receiveCompletion: { status in
print("status>", status)
}) { value in
print("value>", value)
}
输出:
1>: receive subscription: (Empty)
2>: receive subscription: (Print)
2>: request unlimited
1>: request unlimited
1>: receive error: (oops)
2>: receive error: (oops)
status> failure(__lldb_expr_126.MyError.oops)
问题
但是,如果我在前一个管道中插入 receive(on:)
运算符:
enum MyError: Error {
case oops
}
let cancel = Fail<Int, Error>(error: MyError.oops)
.print("1>")
.receive(on: RunLoop.main)
.print("2>")
.sink(receiveCompletion: { status in
print("status>", status)
}) { value in
print("value>", value)
}
输出为:
1>: receive subscription: (Empty)
1>: receive error: (oops)
receive
操作符似乎使管道短路.我还没有看到其他发布者会发生这种情况,只是当我使用 Fail
或 PassthroughSubject
发布者时.
The receive
operator seems to short-circuit the pipeline. I haven't seen it happen for other publishers, just when I use a Fail
or PassthroughSubject
publisher.
这是预期的行为吗?如果是这样,原因是什么?
下面是创建与 receive(on:)
发布者一起使用的失败发布者的示例:
Here's an example of creating a failing publisher that works with the receive(on:)
publisher:
struct FooModel: Codable {
let title: String
}
func failPublisher() -> AnyPublisher<FooModel, Error> {
return Just(Data(base64Encoded: "")!)
.decode(type: FooModel.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
let cancel = failPublisher()
.print("1>")
.receive(on: RunLoop.main)
.print("2>")
.sink(receiveCompletion: { status in
print("status>", status)
}) { value in
print("value>", value)
}
推荐答案
It's possible you're running into the same problem discussed in this post. Apparently receive(on:)
will send all messages asynchronously via the given scheduler, including subscription messages. So what's happening is the error is sent before the the subscription event has a chance to be sent asynchronously, and so there is no subscriber attached to the receive
publisher when the next event comes in.