野指针的bug应该算是最难查的bug之一了,因为其随机性强,且难以定位,下面就终结了几类常见的高概率野指针写法。
1、对象释放后,指针没有置空。
常见写法1:
|
|
问题原因:unsafe_unretained
申明的obj并不会在对象释放时将指针置空,如果对象释放之后,继续使用obj就有可能出现野指针的问题。
解决方案:
尽量使用weak|strong|copy
等来代替unsafe_unretained
来修饰属性。如果一定要使用unsafe_unretained
,记得对象释放后,将指针置空。
常见写法2:
在objc_setAssociatedObject
方法中该用OBJC_ASSOCIATION_RETAIN_NONATOMIC
修饰的对象误用成OBJC_ASSOCIATION_ASSIGN
问题原因:
这个问题和上面的常见写法1问题是类似的,就不重复了。
常见写法3:
NSNotification/KVO 只addObserver并没有removeObserver
|
|
问题原因:
self.obj添加了self作为观察者后,是通过unsafe_unretained
指针引用的self,如果对象释放之前不移除观察,self.obj对应keyPath发生变化时,仍然会去尝试给self指向的对象发送通知。就可能会出现野指针了。
解决方案:
1、原始方法,记得addObserver和removeObserver成对出现。
2、利用KVOController
2、对象提前释放了
常见写法1:
异步方法block回调中,没有强引用self。
|
|
问题原因:
ARC下,由于性能原因self既不是strong也不是weak,而是unsafe_unretained
的。上面代码block并没有引用强引用self。若是在执行[weakSelf someMethod]时,刚好self被释放了,那么self.test 这句的执行就有可能造成野指针崩溃。
解决方案:
在进入block时,先强引用weakself。
|
|
常见写法2:
|
|
问题原因:
由于self在pop之后就会被释放,在pop之后,继续使用self,就可能会导致野指针。
解决方案:
在pop和dismiss之后不要在使用self,关于self的操作都在pop和dismiss之前。
3、对象的多次释放。
常见写法1:
多个线程同时对某个对象赋值
|
|
问题原因:
在调用setArray:时,新的值会被retain,旧的值会被release。如果两个线程同时执行了setArray:,那么旧的值就可能会release放两次。
解决方案:
找个问题不难解决,对象赋之前先加锁,再赋值就可以解决这类问题。
常见写法2:
CoreFoundation层对象Toll-Free Bridging到Foundation层中,已经用了__bridge_transfer关键字转移了对象的所有权之后,又对CoreFoundation层对象调用了一次CFRelease
|
|
问题原因:
使用__bridge_transfer
之后,cfString的所有权已经交由ARC处理,这时再次接手动调用release,会导致重复释放的问题。
解决方案:
1、将__bridge_transfer
改为__bridge
,不转移对象的所有权。
2、去掉CFRelease(cfString)
;
本文作者: ctinusdev
本文链接: https://ctinusdev.github.io/2017/03/03/WriteWildPointer/
转载请注明出处!