笔记继续,接着内存管理、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_retainAutoreleasedReturnValue
和objc_autoreleaseReturnValue
两者,两者成对出现,使函数最优化程序运行。它们可以不将对象注册到 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源码,像里面的一些优化,确实做的很到位,虽说一下子学不下来具体实现,但是思维的学习还是可以改善自己的。