gpt4 book ai didi

swift - 如何使用 Combine 遍历发布者的输出?

转载 作者:行者123 更新时间:2023-11-28 11:30:24 28 4
gpt4 key购买 nike

我正在努力重写我的 Hacker News 阅读器以更多地使用 Combine。我有两个函数都返回 AnyPublisher,其中一个从服务器获取一堆 HN 故事的 ID,另一个通过它的 ID 获取一个故事。我不确定如何遍历 fetchStoryIds 的结果,使用 id 运行 fetchStory 并以 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)
}
}
}
}

最佳答案

嗯.. 似乎没有接受出版商集合的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

虽然我会认为框架中会有这样的东西。

关于swift - 如何使用 Combine 遍历发布者的输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56958539/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com