iOS 中 weak 使用 自动置nil dealloc中为什么不能使用__weak

在开发中weak关键字使用的比较多,一般开发人员都知道,使用weak可以防止循环引用。但是防止循环引用之前是使用unsafe_unretained关键字,使用unsafe_unretained关键字会导致野指针的问题,所以后来才使用weak关键字。

使用weak的好处是可以解决循环引用问题,并且不会有野指针的问题。不会导致程序崩溃,是因为用weak修饰的对象,系统会在对象销毁时把weak指针置nil,但是这样的话,因为系统维护了一个weak的hash表,所以性能上会有点问题,但是相对于程序的可靠性来说,这些性能可以忽略不计,还是推荐使用weak关键字。

最近自己实现了下系统的通知中心,没有实现block的方式,但是通知中心的所有功能都实现了。在实现通知中心的过程中,就遇到了weak的使用。

实现系统通知中心的功能之前,也查了好多资料,说ios9之后就不需要手动移除通知了,因为ios9之前,添加的observer是使用unsafe_unretained关键字修饰的,ios9之后是使用weak修饰的。所以ios9之前如果不移除通知的话,会造成程序崩溃。

这是最终的模型


下面说下我在实现通知中心observer属性修饰符的选择上的心路历程。

最开始我是使用strong,造成的结果是,对象根本无法释放,造成内存泄漏问题。造成的原因是通知中心是单例,单例不会释放,对observer造成强引用。

接下来,我为了验证ios9之前使用unsafe_unretained修饰,如果不移除通知会造成野指针崩溃问题。我把修饰符改为unsafe_unretained,在发送通知时,确实因为野指针的问题,造成了程序崩溃。

后来,我就改为了weak修饰,使用weak修饰后,在发送通知时,调用方法执行,因为weak修饰的对象,对象销毁后,会把weak指针置nil,ios中对nil发送消息,什么也不会操作。

还有在网上看到说在dealloc方法中使用__weak修饰会崩溃的问题,想了下造成崩溃的原因。

因为在实现通知中心时,按照系统的通知中心,移除通知的方法应该在dealloc方法中调用。

我的逻辑是在通知中心的hash表中,找到需要移除的对象进行移除操作,但是在测试过程中发现,通知中心的hash表中的对象已经置为nil了,所以刚开始我用两个对象相等来判断,结果总是false。

后来看了下runtime的源码,说的是在dealloc方法中系统会去调用把weak指针置nil的操作。

所以也就解释了,为什么在dealloc方法中不能使用__weak修饰了。

因为在dealloc方法中系统需要调用把weak指针置nil的操作,如果在dealloc方法中还可以使用__weak修饰的话,那就没有时机让系统把weak指针置nil了。


猜你喜欢

转载自blog.csdn.net/miaogehehe/article/details/80861582
今日推荐