【发布时间】:2021-10-03 07:24:40
【问题描述】:
我在我的 Xcode Playground 中构建了一个简化的组合管道,用于从一系列汽车 [Car] 中生成汽车对象 [CarWithImage]。这似乎工作正常。但我希望管道检查每个汽车对象的imageString,如果不是零,则使用函数getImage(_:) 获取它。我已将该代码注释掉,因为我收到错误 type of expression is ambiguous without more context 并且我不知道如何解决它。我还想在管道中引入延迟,以更真实地模拟汽车和图像的网络下载,如果图像获取失败,则将 CarWithImage 图像属性设置为 nil。
我在 GitHub 上有一个 Xcode Playground 存储库,您可以在其中测试我的代码。第一页是原始类,第二页是试用 compactMap:Cars Playground
代码将在 Xcode Playground 中运行:
import UIKit
import Combine
struct Car {
let name: String
let imageString: String?
}
struct CarWithImage {
let name: String
let image: UIImage?
}
final class CarClass {
let myCars = [Car(name: "Tesla", imageString: "car"), Car(name: "Volvo", imageString: nil)]
let delayCar = 4
let delayImage = 6
func getVehicles() -> AnyPublisher<[CarWithImage], Error> {
myCars.publisher
.flatMap { car in
// if let imageString = car.imageString {
// getImage(imageString)
// .flatMap { image in
// return Just(CarWithImage(name: car.name, image: image))
// }
// }
return Just(CarWithImage(name: car.name, image: nil))
}
.collect()
.flatMap { cars in
cars.publisher.setFailureType(to: Error.self)
}
.collect()
.eraseToAnyPublisher()
}
func getImage(_ string: String) -> AnyPublisher<UIImage, Error> {
Just(UIImage(systemName: string)!)
.flatMap { image in
Just(image).setFailureType(to: Error.self)
}
.eraseToAnyPublisher()
}
}
let carClass = CarClass()
carClass.getVehicles()
.sink(receiveCompletion: { print($0)}) { cars in
cars.forEach { car in
let haveImage = car.image != nil
let string = haveImage ? "and it have an image" : ""
print("The car is", car.name, string)
}
}
// This is just to check that the getImage function works
carClass.getImage("car")
.sink(receiveCompletion: { print($0)}) { image in
print("Got image", image)
}
在建议使用compactMap后,我修改了类,但现在我只在汽车有图像时才得到汽车:
final class CarClass {
let myCars = [Car(name: "Tesla", imageString: "bolt.car"), Car(name: "Volvo", imageString: nil)]
let delayCar = 4
let delayImage = 6
func getVehicles() -> AnyPublisher<[CarWithImage], Error> {
myCars.publisher
.flatMap { car in
self.getImage(car.imageString)
.compactMap { $0 }
.flatMap { image in
return Just(CarWithImage(name: car.name, image: image))
}
}
.collect()
.flatMap { cars in
cars.publisher.setFailureType(to: Error.self)
}
.collect()
.eraseToAnyPublisher()
}
func getImage(_ string: String?) -> AnyPublisher<UIImage?, Error> {
guard let imageString = string else { return Just(nil).setFailureType(to: Error.self).eraseToAnyPublisher() }
return Just(UIImage(systemName: imageString))
.flatMap { image in
Just(image).setFailureType(to: Error.self)
}
.eraseToAnyPublisher()
}
}
【问题讨论】:
-
看看 CompactMap 发布者。用 myCars.publisher.compactMap.flatMap 替换 myCars.publisher.flatMap,返回您在 compactMap 中的可选 imageString。然后在 flatMap 中返回您的 getImage 发布者。 developer.apple.com/documentation/combine/publishers/compactmap