You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 12:17:13