我正在重写我的Hacker News阅读器,以更广泛地使用Combine。我有两个函数都返回一个AnyPublisher
,其中一个从服务器获取一堆HN故事的ID,另一个通过ID获取故事。我不确定如何遍历fetchStoryIds
的结果,使用id运行fetchStory
并最终使用Combine将最终生成Story
个对象数组。
import Combine
import Foundation
struct HackerNewsService {
private var session = URLSession(configuration: .default)
static private var baseURL = "https://hacker-news.firebaseio.com/v0"
private func fetchStoryIds(feed: FeedType) -> AnyPublisher<[Int], Error> {
let url = URL(string: "\(HackerNewsService.baseURL)/\(feed.rawValue.lowercased())stories.json")!
return session.dataTaskPublisher(for: url)
.retry(1)
.map { $0.data }
.decode(type: [Int].self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
private func fetchStory(id: Int) -> AnyPublisher<Story, Error> {
let url = URL(string: "\(HackerNewsService.baseURL)/item/\(id).json")!
return session.dataTaskPublisher(for: url)
.map { $0.data }
.decode(type: Story.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
}
在开始重写之前,我使用此代码遍历id并获取故事。
func fetchStories(feed: FeedType, completionHandler: @escaping ([Story]?, Error?) -> Void) {
fetchStoryIds(feed: feed) { (ids, error) in
guard error == nil else {
completionHandler(nil, error)
return
}
guard let ids = ids else {
completionHandler(nil, error)
return
}
let dispatchGroup = DispatchGroup()
var stories = [Story]()
for id in ids {
dispatchGroup.enter()
self.fetchStory(id: id) { (story, error) in
guard error == nil else {
dispatchGroup.leave()
return
}
guard let story = story else {
dispatchGroup.leave()
return
}
stories.append(story)
dispatchGroup.leave()
}
}
dispatchGroup.notify(queue: .main) {
completionHandler(stories, nil)
}
}
}
}
答案 0 :(得分:2)
嗯。看起来好像没有Publishers.ZipMany
接受出版商的收藏,所以我改为合并故事并收集它们。理想情况下,这将以正确的顺序收集它们,但我尚未对其进行测试,并且在Combine上,文档仍然有些稀疏。
func fetchStories(feed: FeedType) -> AnyPublisher<[Story], Error> {
fetchStoryIds(feed: feed)
.flatMap { ids -> AnyPublisher<[Story], Error> in
let stories = ids.map { self.fetchStory(id: $0) }
return Publishers.MergeMany(stories)
.collect()
.eraseToAnyPublisher()
}
.eraseToAnyPublisher()
}
如果您愿意接受外部代码,则这是ZipMany的主要实现,它将保留顺序: https://gist.github.com/mwahlig/725fe5e78e385093ba53e6f89028a41c
尽管我认为这样的事情会在框架中存在。