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

Swift Combine 从离线模式恢复后的异常行为问题求解

问题根本原因确认

你的推测完全正确,该异常就是旧订阅未及时释放导致的。

具体触发逻辑

  • 你最初使用Set<AnyCancellable>存储订阅时,每次点击按钮触发请求,都会创建新的Publishers.CombineLatest订阅插入集合中。而你监听的$isComplete是@Published属性生成的Publisher,属于无失败类型(Failure为Never),只要ViewModel实例没有被销毁,该Publisher永远不会主动发送完成事件,所以即使对应请求已经失败,旧订阅也不会自动终止、也不会从Set中移除,会持续处于活跃状态。
  • 第一次离线点击触发请求时,两个请求均失败,isComplete未被置为true,第一次创建的CombineLatest订阅就一直留在Set中等待触发条件。
  • 第二次联网点击触发请求时,你又向Set中插入了一个新的CombineLatest订阅,等两个请求完成、isComplete均为true时,新旧两个订阅都会命中触发条件,自然就会执行两次sink回调。

你的解决方案生效逻辑

你将存储容器改为单个AnyCancellable变量,每次发起新请求前主动取消旧订阅,刚好解决了旧订阅留存的问题:新请求发起时旧订阅会被主动cancel,对应的回调逻辑会立即失效,自然不会再收到后续的变更通知,也就不会出现重复回调。

可选优化方案

  • 如果仍想使用Set<AnyCancellable>存储,可以在每次发起新请求前调用cancellables.removeAll()清空所有旧订阅,也能达到相同效果。
  • 也可以在CombineLatest的调用链后追加.prefix(1)修饰符,让订阅在收到第一个符合条件的输出后自动终止,不需要手动管理订阅销毁,更贴合Combine的声明式设计。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 12:15:05