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

Timer闭包调用Singleton函数触发EXC_BAD_ACCESS(SIGBUS)崩溃求助

修复EXC_BAD_ACCESS(KERN_INVALID_ADDRESS)崩溃的方案

从崩溃日志来看,问题出在Swift String桥接为Objective-C对象时的引用计数操作(swift_unknownObjectRetain),触发场景是Timer回调中调用Core Data保存方法。结合你的代码,以下是具体修复措施:

1. 解决Timer的循环引用问题

Timer的闭包会默认捕获当前ViewController的self,形成Timer -> 闭包 -> self -> insertTimer -> Timer的循环引用,导致ViewController无法正常释放,后续回调时访问已释放的内存引发崩溃。修改代码添加弱引用:

private func startInsertTimer() {
    insertTimer?.invalidate()
    insertTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
        guard let self = self else { return } // self已释放时直接退出
        if let data = VDSUtil.shared.vdsString, let vin = VDSUtil.shared.vin {
            DBUtil.shared.saveVehicleStatus(data: data, vin: vin)
        }
    }
}

同时在ViewController销毁时主动清理Timer:

deinit {
    insertTimer?.invalidate()
    insertTimer = nil
}

2. 确保Core Data操作线程安全

Core Data的NSManagedObjectContext并非线程安全,即使当前回调在主线程,若存在多线程操作Context的情况,也可能导致内存异常。修改DBUtil的保存方法,强制在Context的队列中执行操作:

func saveVehicleStatus(data: String, vin: String) {
    let managedContext = AppDelegate.sharedAppDelegate.coreDataStack.managedContext
    managedContext.perform {
        let vStatus = VehicleStatus(context: managedContext)
        vStatus.data = data
        vStatus.vin = vin
        vStatus.date = Date()
        do {
            try managedContext.save()
        } catch {
            print("Core Data保存失败: \(error)")
            // 可添加日志上报逻辑
        }
    }
}

注意:如果你的saveContext方法内部有额外逻辑,也要确保它是线程安全的,避免跨线程调用。

3. 保证VDSUtil单例的线程安全

如果VDSUtil.shared的vdsString和vin属性在多线程下被读写,可能导致String内部结构损坏,桥接时触发内存错误。为这两个属性添加线程保护:

class VDSUtil {
    static let shared = VDSUtil()
    private let syncQueue = DispatchQueue(label: "com.yourapp.vds.sync")
    private var _vdsString: String?
    private var _vin: String?
    
    var vdsString: String? {
        get { syncQueue.sync { _vdsString } }
        set { syncQueue.sync { _vdsString = newValue } }
    }
    
    var vin: String? {
        get { syncQueue.sync { _vin } }
        set { syncQueue.sync { _vin = newValue } }
    }
}

4. 增加字符串有效性校验

虽然已经用if let解包,但可以额外过滤空字符串或异常数据,减少潜在风险:

if let data = VDSUtil.shared.vdsString, !data.isEmpty, 
   let vin = VDSUtil.shared.vin, !vin.isEmpty {
    DBUtil.shared.saveVehicleStatus(data: data, vin: vin)
}

这些措施覆盖了内存引用、线程安全、数据有效性三个核心问题,应该能解决这次偶发的崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 11:36:19