我有一个源发布者,还有一个依赖源发布者的发布者。这是针对我的情况的游乐场测试代码:
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)
}
但是我在控制台只收到一个错误:
Receive error: invalidImage
这是不理想的,我想继续接收值,即使convertImageToVideo方法发生错误。所以我修改代码:
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)
}
这次输出是理想的:
Receive new video: failure(__lldb_expr_64.NetError.invalidImage)
Send 50 into image.
Receive new video: success(50)
但是错误不是来自completion
闭包,而是来自new value
闭包,我必须处理complete
和new value
闭包的错误。有人有好主意吗?谢谢!
您遇到的问题是,当您的image
发布者遇到错误时,它会完成序列。你真正想要流经你的序列是一个Result
说是否每个图像转换工作。要做到这一点,convertImageToVideo
需要发出Result
值,而不仅仅是图像值。这导致你的Future
的一些相当时髦的结果,因为它的未来总是成功的,然后告诉你是否转换工作。
这是你的代码,重新设计,使结果通过:
进口的基础进口相结合进口PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
typealias Image = Int
enum NetError: Error {
case invalidImage
}
func convertImageToVideo(_ image: Image) -> AnyPublisher<Result<Image,Error>, Never> {
Future { promise in
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
if image == 20 {
promise(.success(.failure(NetError.invalidImage)))
} else {
promise(.success(.success(image)))
}
}
}
.eraseToAnyPublisher()
}
var image = PassthroughSubject<Image, Never>()
let subscription = image
.flatMap { image in
convertImageToVideo(image)
}
.sink { video in
switch video {
case .success(let video):
print("Receive new video: (video)")
case .failure(let error):
print("Receive error: (error)")
}
}
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)
}
输出为:
Receive new video: 0
Receive error: invalidImage
Receive error: invalidImage
Receive new video: 40
Send 50 into image.
Receive new video: 50