带你简单理解weak和__weak的实现?


其实类似weak和__weak的实现网上随便一搜就能找到无数篇,有些分析的确实非常不错,但是或许有些人刚好就没有那个耐心去看完,有些人就算最后看完也没有理解,甚至还是没能理解其中的核心,所以这里我就根据个人的理解和网上资料的整理,简单的总结一下……

weak

字面含义就是弱引用,Objective-C中默认都是强引用的(strong)

weak的实现

Runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象的地址)数组。

weak 的实现原理可以概括一下三步:

1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。

2、添加引用时:objc_initWeak函数会调用 objc_storeWeak() 函数, objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表。

3、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。

__weak

__weak修饰符的对象,作用等同于定义为weak的property。他并不会导致循环引用问题(通过苹果文档我们可以得出这样的结论),当原对象没有任何强引用的时候,弱引用指针也会被设置为nil。

__weak的实现

简单来说,系统有一个全局的 CFMutableDictionary 实例,来保存每个对象的 weak 指针列表,因为每个对象可能有多个 weak 指针,所以这个实例的值是 CFMutableSet(Array) 类型。

剩下我们要做的,就是在引用计数变成 0 的时候,去这个全局的字典里面,找到所有的 weak 指针,将其值设置成 nil。如何做到这一点呢?Friday QA 上介绍了一种类似 KVO 实现的方式。当对象存在 weak 指针时,我们可以将这个实例指向一个新创建的子类,然后修改这个子类的 release 方法,在 release 方法中,去从全局的

CFMutableDictionary 字典中找到所有的 weak 对象,并且设置成 nil。我摘抄了 Friday QA 上的实现的核心代码,如下:

Class subclass = objc_allocateClassPair(class, newNameC, 0);
Method release = class_getInstanceMethod(class, @selector(release));
Method dealloc = class_getInstanceMethod(class, @selector(dealloc));
class_addMethod(subclass, @selector(release), (IMP)CustomSubclassRelease, method_getTypeEncoding(release));
class_addMethod(subclass, @selector(dealloc), (IMP)CustomSubclassDealloc, method_getTypeEncoding(dealloc));
objc_registerClassPair(subclass);

总结一句就是:一个通俗的解释就是,在Objective-C的运行时环境中,维护了一种weak表,这张哈希表用对象的首地址作为键,将由若干个weak修饰的指针自身的地址组成的数组作为值。当一个Objective-C对象被释放后,通过这个对象的起始地址来找到所有指向它的weak指针,并将它们指向nil。

__weak的作用

在Objective-C中,用__weak修饰的指针,会在所指向的那个Objective-C对象被释放后,自动指向nil。

使用__weak来修饰指针,相比于__unsafe_unretained,可以帮助程序员减小访问野指针的风险,方便了程序员对内存的管理。

block和weak的区别

前面提到了block,也大概说了一下其简单实现,所以这里总结一下block和__weak修饰符的区别:

1.__block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。
2.__weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)。
3.__block对象可以在block中被重新赋值,__weak不可以。
4.__block对象在ARC下可能会导致循环引用,非ARC下会避免循环引用,__weak只在ARC下使用,可以避免循环引用。
坚持原创技术分享,您的支持将鼓励我继续创作!