Swift Combine:如何条件性返回Future实现接口调用逻辑
解决方案
首先,你遇到的核心问题是Future是一次性的Publisher,直接混用flatMap会导致返回类型不匹配。结合现有Combine架构,我们可以通过两种方式实现需求:
方法一:改用AnyPublisher(推荐)
既然整个网络层都基于Combine,返回AnyPublisher<Void, Error>比Future更灵活,能自然支持链式条件逻辑,避免类型冲突:
func sync() -> AnyPublisher<Void, Error> { service.getItems .receive(on: scheduler) .flatMap { [weak self] items -> AnyPublisher<Void, Error> in guard let self = self else { return Fail(error: NSError(domain: "Self deallocated", code: -1, userInfo: nil)).eraseToAnyPublisher() } self.saveItems(items) guard items.isEmpty else { // 数据不为空,直接返回成功信号 return Just(()).setFailureType(to: Error.self).eraseToAnyPublisher() } // 数据为空,调用备选API并保存结果 return self.service.getAlternativeItems .receive(on: self.scheduler) .handleEvents(receiveValue: { self.saveItems($0) }) .map { _ in () } // 转换为Void类型匹配返回值 .eraseToAnyPublisher() } .eraseToAnyPublisher() }
方法二:坚持返回Future
如果必须保持函数返回Future<Void, Error>,可以把整个链式流程包装到Future内部,既满足类型要求又实现条件逻辑:
func sync() -> Future<Void, Error> { Future { [weak self] promise in guard let self = self else { promise(.failure(NSError(domain: "Self deallocated", code: -1, userInfo: nil))) return } self.service.getItems .receive(on: self.scheduler) .flatMap { items -> AnyPublisher<Void, Error> in self.saveItems(items) guard items.isEmpty else { return Just(()).setFailureType(to: Error.self).eraseToAnyPublisher() } return self.service.getAlternativeItems .receive(on: self.scheduler) .handleEvents(receiveValue: { self.saveItems($0) }) .map { _ in () } .eraseToAnyPublisher() } .sink( receiveCompletion: { completion in switch completion { case .failure(let error): promise(.failure(error)) case .finished: promise(.success(())) } }, receiveValue: { _ in } ) .store(in: &self.subscriptions) } }
关键说明
- flatMap的作用:确保第二个请求在第一个请求完成后执行,根据返回结果动态决定后续流程。
- 类型统一:使用
eraseToAnyPublisher()抹平不同Publisher的类型差异,避免编译器报错。 - 内存安全:全程使用
[weak self]避免循环引用,解包后再执行操作保证安全性。
内容的提问来源于stack exchange,提问作者Michael Harper
相关产品推荐
相关产品推荐

