Swift Combine - 访问单独的发布者列表
Swift Combine - Accessing separate lists of publishers
我有两个 URL 列表,return 一些图像链接。
这些列表被传递到未来
static func loadRecentEpisodeImagesFuture(request: [URL]) -> AnyPublisher<[RecentEpisodeImages], Never> {
return Future { promise in
print(request)
networkAPI.recentEpisodeImages(url: request)
.sink(receiveCompletion: { _ in },
receiveValue: { recentEpisodeImages in
promise(.success(recentEpisodeImages))
})
.store(in: &recentImagesSubscription)
}
.eraseToAnyPublisher()
}
调用:
/// Get a list of image sizes associated with a featured episode .
func featuredEpisodeImages(featuredUrl: [URL]) -> AnyPublisher<[FeaturedEpisodeImages], Error> {
let featuredEpisodesImages = featuredUrl.map { (featuredUrl) -> AnyPublisher<FeaturedEpisodeImages, Error> in
return URLSession.shared
.dataTaskPublisher(for: featuredUrl)
.map(\.data)
.decode(type: FeaturedEpisodeImages.self, decoder: decoder)
.receive(on: networkApiQueue)
.catch { _ in Empty<FeaturedEpisodeImages, Error>() }
.print("###Featured###")
.eraseToAnyPublisher()
}
return Publishers.MergeMany(featuredEpisodesImages).collect().eraseToAnyPublisher()
}
/// Get a list of image sizes associated with a recent episode .
func recentEpisodeImages(recentUrl: [URL]) -> AnyPublisher<[RecentEpisodeImages], Error> {
let recentEpisodesImages = recentUrl.map { (recentUrl) -> AnyPublisher<RecentEpisodeImages, Error> in
return URLSession.shared
.dataTaskPublisher(for: recentUrl)
.map(\.data)
.decode(type: RecentEpisodeImages.self, decoder: decoder)
.receive(on: networkApiQueue)
.catch { _ in Empty<RecentEpisodeImages, Error>() }
.print("###Recent###")
.eraseToAnyPublisher()
}
return Publishers.MergeMany(recentEpisodesImages).collect().eraseToAnyPublisher()
}
并附加到应用状态:
/// Takes an action and returns a future mapped to another action.
static func recentEpisodeImages(action: RequestRecentEpisodeImages) -> AnyPublisher<Action, Never> {
return loadRecentEpisodeImagesFuture(request: action.request)
.receive(on: networkApiQueue)
.map({ images in ResponseRecentEpisodeImages(response: images) })
.replaceError(with: RequestFailed())
.eraseToAnyPublisher()
}
好像是:
return Publishers.MergeMany(recentEpisodes).collect().eraseToAnyPublisher()
没有给我可靠的下游值,因为最后完成的响应会覆盖较早的响应。
我能够记录这两个请求系列的响应。两者都在处理正确的数组和 returning 正确的 json.
我想要这样的东西:
return recentEpisodeImages
但目前这给了我错误
Cannot convert return expression of type '[AnyPublisher<RecentEpisodeImages, Error>]' to return type 'AnyPublisher<[RecentEpisodeImages], Error>'
如何收集内部发布者的值并将它们return作为
AnyPublisher<[RecentEpisodeImages], Error>
假设问题是如何将 URL 的数组转换为下载和处理来自 URL 的数据时得到的数组,答案是:转将数组转换为序列发布者,通过 flatMap
处理每个 URL,并 collect
结果。
例如,这里是如何将表示图像的 URL 数组转换为实际图像数组(与您尝试做的不完全相同,但可能非常接近):
func publisherOfArrayOfImages(urls:[URL]) -> AnyPublisher<[UIImage],Error> {
urls.publisher
.flatMap { (url:URL) -> AnyPublisher<UIImage,Error> in
return URLSession.shared.dataTaskPublisher(for: url)
.compactMap { UIImage(data: [=10=].0) }
.mapError { [=10=] as Error }
.eraseToAnyPublisher()
}.collect().eraseToAnyPublisher()
}
测试方法如下:
let urls = [
URL(string:"http://www.apeth.com/pep/moe.jpg")!,
URL(string:"http://www.apeth.com/pep/manny.jpg")!,
URL(string:"http://www.apeth.com/pep/jack.jpg")!,
]
let pub = publisherOfArrayOfImages(urls:urls)
pub.sink { print([=11=]) }
receiveValue: { print([=11=]) }
.store(in: &storage)
您会看到从管道底部弹出的是一个包含三个图像的数组,对应于我们开始时包含三个 URL 的数组。
(请注意,结果数组的 顺序 是随机的。我们异步获取图像,因此结果以他们喜欢的任何顺序返回到我们的机器。有很多方法可以解决这个问题,但这不是你问的问题。)
我有两个 URL 列表,return 一些图像链接。 这些列表被传递到未来
static func loadRecentEpisodeImagesFuture(request: [URL]) -> AnyPublisher<[RecentEpisodeImages], Never> {
return Future { promise in
print(request)
networkAPI.recentEpisodeImages(url: request)
.sink(receiveCompletion: { _ in },
receiveValue: { recentEpisodeImages in
promise(.success(recentEpisodeImages))
})
.store(in: &recentImagesSubscription)
}
.eraseToAnyPublisher()
}
调用:
/// Get a list of image sizes associated with a featured episode .
func featuredEpisodeImages(featuredUrl: [URL]) -> AnyPublisher<[FeaturedEpisodeImages], Error> {
let featuredEpisodesImages = featuredUrl.map { (featuredUrl) -> AnyPublisher<FeaturedEpisodeImages, Error> in
return URLSession.shared
.dataTaskPublisher(for: featuredUrl)
.map(\.data)
.decode(type: FeaturedEpisodeImages.self, decoder: decoder)
.receive(on: networkApiQueue)
.catch { _ in Empty<FeaturedEpisodeImages, Error>() }
.print("###Featured###")
.eraseToAnyPublisher()
}
return Publishers.MergeMany(featuredEpisodesImages).collect().eraseToAnyPublisher()
}
/// Get a list of image sizes associated with a recent episode .
func recentEpisodeImages(recentUrl: [URL]) -> AnyPublisher<[RecentEpisodeImages], Error> {
let recentEpisodesImages = recentUrl.map { (recentUrl) -> AnyPublisher<RecentEpisodeImages, Error> in
return URLSession.shared
.dataTaskPublisher(for: recentUrl)
.map(\.data)
.decode(type: RecentEpisodeImages.self, decoder: decoder)
.receive(on: networkApiQueue)
.catch { _ in Empty<RecentEpisodeImages, Error>() }
.print("###Recent###")
.eraseToAnyPublisher()
}
return Publishers.MergeMany(recentEpisodesImages).collect().eraseToAnyPublisher()
}
并附加到应用状态:
/// Takes an action and returns a future mapped to another action.
static func recentEpisodeImages(action: RequestRecentEpisodeImages) -> AnyPublisher<Action, Never> {
return loadRecentEpisodeImagesFuture(request: action.request)
.receive(on: networkApiQueue)
.map({ images in ResponseRecentEpisodeImages(response: images) })
.replaceError(with: RequestFailed())
.eraseToAnyPublisher()
}
好像是:
return Publishers.MergeMany(recentEpisodes).collect().eraseToAnyPublisher()
没有给我可靠的下游值,因为最后完成的响应会覆盖较早的响应。
我能够记录这两个请求系列的响应。两者都在处理正确的数组和 returning 正确的 json.
我想要这样的东西:
return recentEpisodeImages
但目前这给了我错误
Cannot convert return expression of type '[AnyPublisher<RecentEpisodeImages, Error>]' to return type 'AnyPublisher<[RecentEpisodeImages], Error>'
如何收集内部发布者的值并将它们return作为
AnyPublisher<[RecentEpisodeImages], Error>
假设问题是如何将 URL 的数组转换为下载和处理来自 URL 的数据时得到的数组,答案是:转将数组转换为序列发布者,通过 flatMap
处理每个 URL,并 collect
结果。
例如,这里是如何将表示图像的 URL 数组转换为实际图像数组(与您尝试做的不完全相同,但可能非常接近):
func publisherOfArrayOfImages(urls:[URL]) -> AnyPublisher<[UIImage],Error> {
urls.publisher
.flatMap { (url:URL) -> AnyPublisher<UIImage,Error> in
return URLSession.shared.dataTaskPublisher(for: url)
.compactMap { UIImage(data: [=10=].0) }
.mapError { [=10=] as Error }
.eraseToAnyPublisher()
}.collect().eraseToAnyPublisher()
}
测试方法如下:
let urls = [
URL(string:"http://www.apeth.com/pep/moe.jpg")!,
URL(string:"http://www.apeth.com/pep/manny.jpg")!,
URL(string:"http://www.apeth.com/pep/jack.jpg")!,
]
let pub = publisherOfArrayOfImages(urls:urls)
pub.sink { print([=11=]) }
receiveValue: { print([=11=]) }
.store(in: &storage)
您会看到从管道底部弹出的是一个包含三个图像的数组,对应于我们开始时包含三个 URL 的数组。
(请注意,结果数组的 顺序 是随机的。我们异步获取图像,因此结果以他们喜欢的任何顺序返回到我们的机器。有很多方法可以解决这个问题,但这不是你问的问题。)