映射 Swift 将未来组合到另一个未来
Mapping Swift Combine Future to another Future
我有一个 returns 未来的方法:
func getItem(id: String) -> Future<MediaItem, Error> {
return Future { promise in
// alamofire async operation
}
}
我想用在另一个方法中,将MediaItem
转换为NSImage
,这是一个同步操作。我希望简单地在原始 Future 上做一个 map
或 flatMap
但它创建了一个我无法擦除到 Future<NSImage, Error>
.
的长 Publisher
func getImage(id: String) -> Future<NSImage, Error> {
return getItem(id).map { mediaItem in
// some sync operation to convert mediaItem to NSImage
return convertToNSImage(mediaItem) // this returns NSImage
}
}
我收到以下错误:
Cannot convert return expression of type 'Publishers.Map<Future<MediaItem, Error>, NSImage>' to return type 'Future<NSImage, Error>'
我尝试使用 flatMap
但出现了类似的错误。我可以 eraseToAnyPublisher
但我认为这隐藏了 getImage(id: String
returns 一个未来的事实。
我想我可以在将来包装 getImage
的主体,但这似乎不如链接和映射那么干净。欢迎任何建议。
您不能像那样使用 Combine 框架中的点点滴滴。您必须制作一个 管道 — 一个发布者、一些操作员和一个订阅者(您将其存储以便管道有机会 运行)。
Publisher
|
V
Operator
|
V
Operator
|
V
Subscriber (and store it)
所以,在这里,getItem
是一个生成你的 Publisher 的函数,一个 Future。所以你可以说
getItem (...)
.map {...}
( maybe other operators )
.sink {...} (or .assign(...))
.store (...)
现在,未来(以及整个管道)将 运行 异步,结果将从管道的末端弹出,您可以用它做一些事情。
现在,您当然可以将 Future 和 Map 放在一起,然后 停止, 出售它们以便其他人 else 可以附加其他运营商和他们的订户。您现在已经组装了管道的起点,仅此而已。但是它的 type 不会是 Future;它将是 AnyPublisher<NSImage,Error>
。这并没有错!
你总是可以将一个未来包裹在另一个未来中。与其将其映射为 Publisher,不如在将来订阅它的结果 return.
func mapping(futureToWrap: Future<MediaItem, Error>) -> Future<NSImage, Error> {
var cancellable: AnyCancellable?
return Future<String, Error> { promise in
// cancellable is captured to assure the completion of the wrapped future
cancellable = futureToWrap
.sink { completion in
if case .failure(let error) = completion {
promise(.failure(error))
}
} receiveValue: { value in
promise(.success(convertToNSImage(mediaItem)))
}
}
}
这总是可以概括为
extension Publisher {
func asFuture() -> Future<Output, Failure> {
var cancellable: AnyCancellable?
return Future<Output, Failure> { promise in
// cancellable is captured to assure the completion of the wrapped future
cancellable = self.sink { completion in
if case .failure(let error) = completion {
promise(.failure(error))
}
} receiveValue: { value in
promise(.success(value))
}
}
}
}
请注意,如果有问题的发布者是 class,它将在未来 returned 的关闭生命周期内保留。此外,作为未来,您只会获得发布的第一个值,之后未来将完成。
最后,简单的擦除到AnyPublisher
就好了。如果您想确保只获得第一个值(类似于获得未来的唯一值),您可以执行以下操作:
getItem(id)
.map(convertToNSImage)
.eraseToAnyPublisher()
.first()
结果类型 Publishers.First<AnyPublisher<Output, Failure>>
具有足够的表现力来传达永远只会收到一个结果,类似于 Future。您甚至可以为此定义一个类型别名(尽管在这一点上可能有点矫枉过正):
typealias AnyFirst<Output, Failure> = Publishers.First<AnyPublisher<Output, Failure>>
我有一个 returns 未来的方法:
func getItem(id: String) -> Future<MediaItem, Error> {
return Future { promise in
// alamofire async operation
}
}
我想用在另一个方法中,将MediaItem
转换为NSImage
,这是一个同步操作。我希望简单地在原始 Future 上做一个 map
或 flatMap
但它创建了一个我无法擦除到 Future<NSImage, Error>
.
func getImage(id: String) -> Future<NSImage, Error> {
return getItem(id).map { mediaItem in
// some sync operation to convert mediaItem to NSImage
return convertToNSImage(mediaItem) // this returns NSImage
}
}
我收到以下错误:
Cannot convert return expression of type 'Publishers.Map<Future<MediaItem, Error>, NSImage>' to return type 'Future<NSImage, Error>'
我尝试使用 flatMap
但出现了类似的错误。我可以 eraseToAnyPublisher
但我认为这隐藏了 getImage(id: String
returns 一个未来的事实。
我想我可以在将来包装 getImage
的主体,但这似乎不如链接和映射那么干净。欢迎任何建议。
您不能像那样使用 Combine 框架中的点点滴滴。您必须制作一个 管道 — 一个发布者、一些操作员和一个订阅者(您将其存储以便管道有机会 运行)。
Publisher
|
V
Operator
|
V
Operator
|
V
Subscriber (and store it)
所以,在这里,getItem
是一个生成你的 Publisher 的函数,一个 Future。所以你可以说
getItem (...)
.map {...}
( maybe other operators )
.sink {...} (or .assign(...))
.store (...)
现在,未来(以及整个管道)将 运行 异步,结果将从管道的末端弹出,您可以用它做一些事情。
现在,您当然可以将 Future 和 Map 放在一起,然后 停止, 出售它们以便其他人 else 可以附加其他运营商和他们的订户。您现在已经组装了管道的起点,仅此而已。但是它的 type 不会是 Future;它将是 AnyPublisher<NSImage,Error>
。这并没有错!
你总是可以将一个未来包裹在另一个未来中。与其将其映射为 Publisher,不如在将来订阅它的结果 return.
func mapping(futureToWrap: Future<MediaItem, Error>) -> Future<NSImage, Error> {
var cancellable: AnyCancellable?
return Future<String, Error> { promise in
// cancellable is captured to assure the completion of the wrapped future
cancellable = futureToWrap
.sink { completion in
if case .failure(let error) = completion {
promise(.failure(error))
}
} receiveValue: { value in
promise(.success(convertToNSImage(mediaItem)))
}
}
}
这总是可以概括为
extension Publisher {
func asFuture() -> Future<Output, Failure> {
var cancellable: AnyCancellable?
return Future<Output, Failure> { promise in
// cancellable is captured to assure the completion of the wrapped future
cancellable = self.sink { completion in
if case .failure(let error) = completion {
promise(.failure(error))
}
} receiveValue: { value in
promise(.success(value))
}
}
}
}
请注意,如果有问题的发布者是 class,它将在未来 returned 的关闭生命周期内保留。此外,作为未来,您只会获得发布的第一个值,之后未来将完成。
最后,简单的擦除到AnyPublisher
就好了。如果您想确保只获得第一个值(类似于获得未来的唯一值),您可以执行以下操作:
getItem(id)
.map(convertToNSImage)
.eraseToAnyPublisher()
.first()
结果类型 Publishers.First<AnyPublisher<Output, Failure>>
具有足够的表现力来传达永远只会收到一个结果,类似于 Future。您甚至可以为此定义一个类型别名(尽管在这一点上可能有点矫枉过正):
typealias AnyFirst<Output, Failure> = Publishers.First<AnyPublisher<Output, Failure>>