求助:调用CMMotionManager的startDeviceMotionUpdatesToQueue时App偶发崩溃
核心原因分析
从崩溃栈和你提到的代码场景来看,这个偶发的EXC_BAD_ACCESS崩溃,大概率是内存生命周期不匹配导致的——当CoreMotion后台还在推送设备运动数据时,你的回调handler里引用的对象(比如页面控制器、业务类)已经被ARC回收了,回调触发时访问了已释放的内存,引发了崩溃。
具体解决办法
把CMMotionManager改成类的强引用属性
如果你的startMotionManager方法里是把motionManager作为局部变量创建的,方法执行完这个对象就会被回收,但CoreMotion内部可能还持有它的引用,后续回调时必然会出现野指针问题。你需要把它改成类的属性来绑定生命周期:class YourViewController: UIViewController { // 用可选类型,方便后续置空清理 private var motionManager: CMMotionManager? func startMotionManager() { motionManager = CMMotionManager() guard let manager = motionManager else { return } manager.deviceMotionUpdateInterval = 1/60.0 // 后续的配置和启动逻辑 } }给回调闭包做安全的内存绑定
在设置deviceMotion的handler时,一定要用[weak self]避免循环引用,同时在闭包开头检查self是否存在,防止访问已释放的对象:manager.startDeviceMotionUpdates(to: .main) { [weak self] motion, error in // 先确认self、motion有效且无错误,再执行业务逻辑 guard let self = self, let motion = motion, error == nil else { // 这里可以做错误日志记录,或者直接退出 return } // 你的运动数据处理逻辑 self.updateUIWithMotion(motion) }及时停止更新并清理资源
当你不需要再获取运动数据时(比如页面即将消失、APP进入后台、业务流程结束),一定要主动停止更新并清空motionManager,切断所有引用:func stopMotionUpdates() { motionManager?.stopDeviceMotionUpdates() // 置空让ARC彻底回收资源 motionManager = nil } // 举个例子,在页面生命周期里调用 override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) stopMotionUpdates() }额外的安全防护
如果你的业务场景比较复杂,还可以在handler里增加更多前置检查,比如判断当前对象是否处于活跃状态,避免执行可能触发崩溃的逻辑。
总结
这个偶发崩溃的本质就是回调触发时机和对象生命周期不匹配,只要把CMMotionManager的生命周期和业务对象绑定,同时在回调里做好安全校验,就能解决这个困扰你的问题。
内容的提问来源于stack exchange,提问作者linitial
相关产品推荐
相关产品推荐

