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

iOS13下同步线程更新Combine Published值导致Swift崩溃如何解决

问题原因

  • iOS 13 系统的 Combine 框架存在已知实现缺陷:使用 receive(on: RunLoop.main) 作为调度器时,无法稳定保证后续回调执行在主队列。而 @Published 属性的变更会触发 UI 刷新,要求必须在主队列执行,子线程赋值时就会触发 EXC_BAD_ACCESS 野指针崩溃。iOS 14 及以上系统修复了该缺陷,所以运行正常。
  • 你提供的 ViewModel 代码中未声明用于存储 Combine 订阅的 cancellable 集合,会导致订阅内存管理异常,也是潜在的崩溃诱因。
  • start 方法中 dispatchQueue.asyncAfter 的闭包未加 [weak self] 修饰,会导致 ViewModel 被调度队列强持有,出现内存泄漏或已销毁实例被访问的问题。
  • 代码存在笔误:发送事件时调用的 pushNotificationTroubleshooterSubject 与你定义的 mainSubject 不符,会导致事件无法正常发送。

解决方案

  1. 替换调度器写法,将 receive(on: RunLoop.main) 改为 receive(on: DispatchQueue.main),这是 iOS 13 下 Combine 的标准兼容写法,可以稳定保证回调执行在主队列。
  2. 在 ViewModel 中补充 cancellable 属性声明:
private var cancellable = Set<AnyCancellable>()
  1. 给所有异步闭包添加 [weak self] 避免循环引用,修改 start 方法的闭包逻辑:
dispatchQueue.asyncAfter(deadline: DispatchTime.now() + 1) { [weak self] in
    guard let self = self else { 
        dispatchSemaphore.signal()
        dispatchGroup.leave()
        return 
    }
    dispatchSemaphore.wait()
    self.getValues {
        PublisherManager.shared.mainSubject.send(.updateValue())
        dispatchSemaphore.signal()
        dispatchGroup.leave()
    }
}
  1. 可额外添加主队列判断做双重保障,修改 updateValue 实现:
private func updateValue() {
    if Thread.isMainThread {
        status = .active
    } else {
        DispatchQueue.main.async { [weak self] in
            self?.status = .active
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 17:15:04