读 Objective-C 高级编程(五)

笔记继续,接着内存管理ARC 规则之后,本篇将重点记录下 ARC 内存管理方式的实现(__strong 修饰符 和__weak 修饰符)。

ARC 的实现

苹果的官方说明中称,ARC 是“由编译器进行内存管理”的,但实际上只有编译器是无法胜任的,在此基础上还需要 Objective-C 运行时库的协助。此处围绕 clang 汇编输出和 objc4库(主要是 runtimr/objc-arr.mm)的源代码进行说明。

__strong 修饰符的实现

下面通过编译器的模拟代码,说明在 alloc,new,copy.mutableCopy 的运行?

 id __strong obj = [[NSObject alloc] init];
id obj = objc_msgSend(NSObject,@selector(alloc));
objc_msgSend(obj,@selector(init));
obj_release(obj);
    

上面的模拟转换中,可以看出此处是两次调用 objc_msgSend 方法(alloc,init),变量作用域结束时通过 objc_release 释放对象。虽然 ARC 有效是,不能使用release方法,由此可知编译器自动插入了 release

另外,我们也要注意除去 alloc,new,copy.mutableCopy 之外的方法说明,例如 NSMutableArray 中的 array

id __strong obj = [NSMutableArray array];
id obj = objc_msgSend(NSMutableArray,@selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_release(obj);

进一步说明

+ (id)array
{
    return [[NSMutableArray alloc] init];
}
id obj = objc_msgSend(MSMutableArray,@selector(alloc));
objc_msgSend(obj,@selector(init));
retrun objc_autoreleaseReturnValue(obj);

此处要注意objc_retainAutoreleasedReturnValueobjc_autoreleaseReturnValue 两者,两者成对出现,使函数最优化程序运行。它们可以不将对象注册到 autoreleasepool 中而直接传递,达到这一过程的的最优化。

省略 autoreleasepool 注册 优化的过程

__weak 修饰符的实现

若附有__weak 修饰符的变量所引用的对象被废弃,则将 nil 赋值给该变量。

 id __weak obj1 = obj;
id obj1;
obj_initWeak(&obj1,obj);
objc_destoryWeak(&obj1);

通过 objc_initWeak 函数初始化附有__weak 修饰符的变量,在变量作用域结束是通过objc_destoryWeak 释放该变量。

但此处要注意obj_initWeak 做的事情: 它将附有__weak 修饰符的变量初始化为0后,会将赋值的对象作为参数调用 objc_storeWeak 函数。

objc_storeWeak(&obj1,obj);

obj_storeWeak 函数将第二个参数的赋值对象的地址作为键值,将第一个参数的附有__weak修饰符地址注册到 weak 表(也是一个散列表)中。如果第二个参数是0,则将该变量的地址从 weak表中去掉,也就实现了若附有__weak 修饰符的变量所引用的对象被废弃,则将 nil 赋值给该变量的功能。

objc_storeWeak(&obj1,obj);
objc_storeWeak(&obj1,0);

使用附有 __weak 修饰符的变量,即是使用注册到 autoreleasepool中的对象。

id __weak obj1 = obj;
id obj1;
obj_initWeak(&obj1,obj);
id tmp = objc_loadWeakRetained(&obj1);
objc_autorelease(tmp);
objc_destoryWeak(&obj1);

此时增加了两个步骤:
(1)、objc_loadWeakRetained 函数取出附有__weak 修饰符变量所引用的对象并 retain。
(2)、objc_autorelease 函数将对象注册到 autoreleasepool中。

由此可知,因为附有__weak 修饰符变量所引用的对象像这样被注册到 autoreleasepool 中,所以在自动释放池结束之前都可以放心使用。但是大量使用附有__weak 修饰符的变量,注册到 autoreleasepool的对象也会大量增加,因此这种大量使用的情况下,最好还是先暂时赋值给附有__strong修饰符的变量后再使用。

通过__weak__strong 修饰符的大致实现后,进一步认识了 ARC 。同时发现真是很有需要读Objc runtime源码,像里面的一些优化,确实做的很到位,虽说一下子学不下来具体实现,但是思维的学习还是可以改善自己的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

友情链接更多精彩内容