一. 背景
项目上线后,偶现了一个崩溃,崩溃堆栈如下,从表面看崩溃的原因是在vc
对象dealloc
的时候,访问了一个懒加载的对象,这时候触发了该对象的弱引用创建。

二. 分析
因为这个崩溃是偶现的,经排查下来,如果VC
页面从初始化到即将dealloc
,都没有调用过这个对象,只在dealloc
访问了首次这个对象的懒加载方法,而这个对象刚好有代理或者block
回调,触发了VC
对象的弱引用的创建,就一定会触发崩溃。
例如如下代码:
在对象dealloc
的时候,首次调用子对象的懒加载方法,都会触发该对象的弱引用的创建,都会触发崩溃。
ini
// 测试视图
- (FJFLazyTestView *)testView {
if (!_testView) {
_testView = [[FJFLazyTestView alloc] init];
_testView.delegate = self; /// 崩溃点
}
return _testView;
}
// 测试视图
- (FJFLazyTestView *)testView {
if (!_testView) {
_testView = [[FJFLazyTestView alloc] init];
__weak typeof(self) weakSelf = self; // 崩溃点
_testView.testBlock = ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) return; // 父对象已销毁时退出
[strongSelf testPrint];
};
}
return _testView;
}
崩溃的直接原因:运行时安全防护
若在 对象dealloc
过程中尝试创建新的该对象弱引用(如 __weak typeof(self) weakSelf = self
):
- 运行时检查对象状态
storeWeak
函数会检测对象是否处于deallocating
状态(通过objc_destructInstance
函数标记)。 - 主动触发崩溃 当检测到对象正在析构时,
storeWeak
会调用objc_fatal
抛出以下崩溃日志:
scss
if (deallocating) {
_objc_fatal("Cannot form weak reference to instance (%p) of class %s.
It is possible that this object was over-released,
or is in the process of deallocation.",
(void*)referent, object_getClassName((id)referent));
} // [2](@ref)
崩溃本质是运行时的主动防护,防止开发者访问即将失效的内存。
三. 治理
将对象dealloc
里面的将子对象改为实例方法访问类似_testView
这样的,或者确保父对象dealloc
之前,一定调用过子对象的懒加载方法。