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不符,会导致事件无法正常发送。
解决方案
- 替换调度器写法,将
receive(on: RunLoop.main)改为receive(on: DispatchQueue.main),这是 iOS 13 下 Combine 的标准兼容写法,可以稳定保证回调执行在主队列。 - 在
ViewModel中补充cancellable属性声明:
private var cancellable = Set<AnyCancellable>()
- 给所有异步闭包添加
[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() } }
- 可额外添加主队列判断做双重保障,修改
updateValue实现:
private func updateValue() { if Thread.isMainThread { status = .active } else { DispatchQueue.main.async { [weak self] in self?.status = .active } } }
内容的提问来源于stack exchange,提问作者mrjimoy_05
相关产品推荐
相关产品推荐

