使用Combine的Zip操作符合并两个返回Result<T, Error>的API请求如何优化?
优化实现方案
你可以直接利用Result自带的get()方法简化取值逻辑,同时把Result解析逻辑提前放到Combine操作链中处理,不需要在sink闭包内手动写switch匹配。优化后的代码如下:
// 提前解析两个Publisher的Result,错误直接在流中处理完成 let postsStream = getPosts() .map { result -> [Post] in do { return try result.get() } catch { print("Error: \(error.localizedDescription)") return [] } } let usersStream = getUsers() .map { result -> [User] in do { return try result.get() } catch { print("Error: \(error.localizedDescription)") return [] } } Publishers.Zip(postsStream, usersStream) .map { posts, users -> [ForumPost] in // 用字典映射优化匹配效率,避免双重循环 let userMapping = users.reduce(into: [Int: String]()) { $0[$1.id] = $1.username } return posts.compactMap { post in guard let username = userMapping[post.userId] else { return nil } return ForumPost(username: username, title: post.title) } } .sink(receiveValue: { [weak self] forumPosts in guard let self = self else { return } print(forumPosts) // 最终结果处理,比如UI赋值、数据存储等 }) .store(in: &publishers)
额外优化建议
如果项目中这类Result类型的Publisher比较多,可以写个扩展复用解析逻辑,进一步简化代码:
extension Publisher where Failure == Never { func resolveResult<T>(printError: Bool = true) -> AnyPublisher<[T], Never> where Output == Result<[T], Error> { map { result in do { return try result.get() } catch { if printError { print("Error: \(error.localizedDescription)") } return [] } } .eraseToAnyPublisher() } }
使用扩展后,两个流的解析代码可以简化为:
let postsStream = getPosts().resolveResult() let usersStream = getUsers().resolveResult()
内容的提问来源于stack exchange,提问作者Wazza
相关产品推荐
相关产品推荐

