Reputation: 35920
The following pipeline:
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)
}
Outputs:
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)
However, if I insert a receive(on:)
operator into the previous pipeline:
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)
}
the output is:
1>: receive subscription: (Empty)
1>: receive error: (oops)
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.
Is this expected behavior? If so, what's the reason for it?
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)
}
Upvotes: 0
Views: 693
Reputation: 5961
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.
However, it looks like they are changing this as of developer beta 1 of iOS 13.3:
As of developer beta 1 of iOS 13.3 (and associated releases for other platforms), we've changed the behavior of receive(on:) plus other Scheduler operators to synchronously send their subscription downstream. Previously, they would "async" it to the provided scheduler.
Upvotes: 2