最近用了一个三方库,线上crash收集日志经常会收集到crash。报的是野指针,所以看不到堆栈信息,通过排查对比新增代码,渐渐锁定问题出现在下面这个函数:
- (void)removeFromSuperview {
[super removeFromSuperview];
self.completionBlock = nil;
[self _removeCurrentAnimationIfNecessary];
}
通过查询资料,得知一个普通的参数,在进入这个函数的时候,会被strong
一次,也就是强引用一次,所以我们不用担心在方法执行到一半的时候,参数被释放的问题。
我们知道OC中的消息机制,调用方法实际上最终最终调用的是objc_msgSend(id self, SEL op, ...)
,从这里我们也可以看出,实际上我们的参数还有2个隐形的,一个是self
,一个是对应的SEL
。这里我们不讨论SEL
。
ARC下,一般的参数都是如我上面所说,是会被strong
的,但是self
这个参数比较特殊,是__unsafe_unretained
引用的,也就是单纯的指针赋值,不改变引用计数,也不会在释放的时候被置为nil
。
如上面的例子,如果这个view
没有在外部被强引用,执行removeFromSuperview
方法,当程序到[super removeFromSuperview]
这行代码之后,这个view
会立马被dealloc
,然而因为self
这个参数没有被置为nil
,所以也就造成了后面调用到self
时报野指针的crash。应该修改为下面的写法。
- (void)removeFromSuperview {
self.completionBlock = nil;
[self _removeCurrentAnimationIfNecessary];
[super removeFromSuperview];
}
网友评论