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

Swift Combine:如何按顺序运行带超时的Publisher?

解决方案

要实现「publisher1完成后运行带超时的publisher2,且无论publisher2成功、超时或出错都让整个流程结束」的需求,你可以通过捕获超时及其他错误并转换为正常完成事件来处理,具体修改如下:

修改后的代码

// 需声明存储订阅的集合,避免订阅被立即释放
var cancellables = Set<AnyCancellable>()

publisher1.flatMap { _ in
    publisher2
        // 为publisher2设置1秒超时,超时后抛出TimeoutError
        .timeout(1, scheduler: RunLoop.main)
        // 捕获所有错误(包括超时和Socket自身抛出的错误),转换为正常完成事件
        .catch { error in
            // 可选:打印错误信息用于调试
            if error is TimeoutError {
                print("publisher2 超时")
            } else {
                print("publisher2 出错: \(error)")
            }
            // 返回空Publisher,触发流的.finished事件
            return Empty(completeImmediately: true)
        }
}
.handleEvents(receiveCancel: {
    // 在此添加Socket资源清理逻辑,比如断开连接
    print("订阅取消,清理Socket资源")
})
.sink(
    receiveCompletion: { completion in
        switch completion {
        case .finished:
            print("整个流程正常结束")
        case .failure:
            // 由于catch已处理所有错误,此处不会触发
            break
        }
    },
    receiveValue: { success in
        print("收到publisher2返回值: \(success)")
    }
)
.store(in: &cancellables) // 必须存储订阅,否则会被系统立即释放

关键逻辑说明

  • timeout操作符:给publisher2设置1秒超时阈值,超时后会抛出TimeoutError,若不处理会导致整个流进入失败状态。
  • catch操作符:捕获publisher2产生的所有错误(包括超时和Socket事件可能抛出的错误),返回一个Empty Publisher——这个Publisher会立即发送.finished事件,让整个流正常结束而非失败终止。
  • 订阅存储:务必将sink返回的AnyCancellable存入集合,否则订阅会被系统立即释放,publisher2无法正常执行。
  • 资源清理:在handleEvents(receiveCancel:)中添加Socket断开、资源释放逻辑,避免内存泄漏。

可选扩展:保留错误标识但仍结束流程

如果你希望在sink中区分「正常完成」和「因错误完成」,可以用Result类型包装返回值:

publisher1.flatMap { _ in
    publisher2
        .timeout(1, scheduler: RunLoop.main)
        .map { Result.success($0) }
        .catch { error in
            return Just(Result.failure(error))
        }
}
.sink(
    receiveCompletion: { _ in
        print("流程结束")
    },
    receiveValue: { result in
        switch result {
        case .success(let value):
            print("成功收到值: \(value)")
        case .failure(let error):
            if error is TimeoutError {
                print("超时错误")
            } else {
                print("其他错误: \(error)")
            }
        }
    }
)
.store(in: &cancellables)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 22:22:28