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

Swift Combine 结合 Clean Architecture 异步任务执行顺序异常排查

问题成因
  1. Combine 中的 Future 属于热发布者,实例创建时就会同步执行其构造闭包,不需要等待订阅动作触发。
  2. 默认情况下 Future 的构造闭包会在当前调用线程(此处为主线程)同步执行,闭包中访问 task 计算属性时,会同步触发 repository.test() 里的 sleep(3) 阻塞当前线程,直到 sleep 结束、执行 promise、sink 收到值打印 1 之后,才会执行到后续的 print("Started") 逻辑,所以输出顺序和预期相反。
  3. 额外隐患:当前你把 cancellables 声明为 init 方法的局部变量,init 执行完毕后变量就会被销毁,存储的订阅会被立即取消,就算修改为异步执行也可能收不到回调。
解决方案

需要做两处核心修改:

  1. 给 Future 指定后台队列执行任务,避免阻塞主线程,保证 print("Started") 先执行
  2. 将 cancellables 提升为类/结构体的成员属性,延长订阅生命周期

修改后的代码示例如下:

修改 UseCaseBase 的 execute 方法

func execute(with payload: TInput) -> AnyPublisher<TOutput, Never> {
    return Future<TOutput, Never> { promise in
        promise(.success(self.task!))
    }
    // 指定任务在后台全局队列异步执行
    .subscribe(on: DispatchQueue.global())
    // 如果后续回调需要操作UI,可加这行切回主线程,不需要可省略
    .receive(on: DispatchQueue.main)
    .eraseToAnyPublisher()
}

修改 ContentView 的属性声明

struct ContentView: View {
    // 提升为成员属性,生命周期和View保持一致
    private var cancellables = Set<AnyCancellable>()

    init() {
        let useCase = MockUseCase(MockRepository())
        
        useCase.execute(with: "String")
            .sink(receiveValue: { value in
                print(value)
            })
            .store(in: &cancellables)
        
        print("Started")
    }

    var body: some View {
        Text("Hello World")
    }
}

修改后调用 execute 时,Future 的任务会被提交到后台队列异步排队,不会阻塞当前主线程,会立刻执行后续的 print("Started");后台队列执行任务时会先 sleep 3秒,完成后再触发 sink 打印 1,符合预期的输出顺序。

内容的提问来源于stack exchange,提问作者Allan Snicker

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 23:18:01