I have a source publisher, and have an another publisher rely source publisher. This is playground test code for my situation:
import Foundation
import Combine
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
typealias Image = Int
enum NetError: Error {
case invalidImage
}
func convertImageToVideo(_ image: Image) -> AnyPublisher<Image, NetError> {
Future { promise in
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
if image == 20 {
promise(.failure(.invalidImage))
} else {
promise(.success(image))
}
}
}
.eraseToAnyPublisher()
}
var image = PassthroughSubject<Image, NetError>()
let subscription = image
.map { image in
convertImageToVideo(image)
}
.switchToLatest()
.sink { completion in
if case let .failure(error) = completion {
print("Receive error: \(error)")
}
} receiveValue: { video in
print("Receive new video: \(video)")
}
image.send(0)
image.send(20)
image.send(40)
DispatchQueue.main.async {
image.send(20)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
print("Send 50 into image.")
image.send(50)
}
But I only receive one error in console:
Receive error: invalidImage
This is not ideal, I want continue receive value even if convertImageToVideo method occur an error. So I change code:
import Foundation
import Combine
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
typealias Image = Int
enum NetError: Error {
case invalidImage
}
func convertImageToVideo(_ image: Image) -> AnyPublisher<Image, NetError> {
Future { promise in
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
if image == 20 {
promise(.failure(.invalidImage))
} else {
promise(.success(image))
}
}
}
.eraseToAnyPublisher()
}
var image = PassthroughSubject<Image, NetError>()
let subscription = image
.map { image -> AnyPublisher<Result<Image, NetError>, Never> in
convertImageToVideo(image)
.map { video in
.success(video)
}
.catch({ error in
Just(.failure(error))
})
.eraseToAnyPublisher()
}
.switchToLatest()
.sink { completion in
if case let .failure(error) = completion {
print("Receive error: \(error)")
}
} receiveValue: { video in
print("Receive new video: \(video)")
}
image.send(0)
image.send(20)
image.send(40)
DispatchQueue.main.async {
image.send(20)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
print("Send 50 into image.")
image.send(50)
}
This time output is ideal:
Receive new video: failure(__lldb_expr_64.NetError.invalidImage)
Send 50 into image.
Receive new video: success(50)
But the error not come from completion
closure, instead of it come from new value
closure, I must handle error from complete
closure and new value
closure.
Anyone has good idea? Thanks!