《OC高级编程》之自动引用计数(三)

2019-03-08  本文已影响0人  毛线sama

ARC实现

 
    ARC 由 clang (LLVM 编译器) 3.0 以上和 objc4 Objective-C 运行时库 493.9 以上实现
 

__strong 修饰符

    2 次调用 objc_msgSend 方法(alloc 和 init),变量作用域结束时通过objc_release 释放对象,编译器自动插入 release

    用除 alloc/new/copy/mutableCopy 外方法时,release 之前调用了objc_retainAutoreleasedReturnValue 函数,与之相对的是objc_autoreleaseReturnValue 函数,用于 alloc/new/copy/mutableCopy 外等返回对象的实现,返回注册到 autoreleasepool 中的对象,但会检查使用该函数的方法或调用方的执行命令列表,如果之后紧接着调用objc_retainAutoreleasedReturnValue 函数,那么就不将对象注册到autoreleasepool,而是直接传递,即便不注册到 autoreleasepool,也可以准确获取对象,这一过程达到了最优化
 

__weak 修饰符

{
    id __weak obj1 = obj;
}

/* 编译器的模拟代码 */
id obj1;
obj1 = 0;
objc_storeWeak(&obj1, obj);
objc_storeWeak(&obj1, 0);

    objc_storeWeak 函数把第二个参数的赋值对象的地址作为键值,将第一参数的附有 __weak 修饰符的变量的地址注册到 weak 表。如果第二参数为 0,则把变量从weak 表删除

    weak 表与引用计数表相同,作为散列表实现。将废弃对象的地址作为键值进行检索,就能高效获取对应的 __ weak 变量的地址。由于一个对象可赋值给多个__weak 变量,所以对一个键值,可注册多个变量地址

    释放对象时,最后调用的 objc_clear_deallocating 函数动作如下:

  1. 从 weak 表获取废弃对象的地址作为键值的记录
  2. 将包含在记录中的所有附有 __weak 修饰符变量的地址,赋值为 nil
  3. 从 weak 表删除该记录
  4. 从引用计数表中删除废弃对象的地址为键值的记录

    可见,如果大量使用 __weak,会消耗相应的 CPU,所以只在需要避免循环引用时使用

id __weak obj = [[NSObject alloc] init];
id __unsafe_unretained obj = [[NSObject alloc] init];
//编译器警告

[[NSObject alloc] init];
//ARC 无效时会发生内存泄漏
(void)[[NSObject alloc] init];
//避免警告
//ARC 有效时,编译器生成并立即调用 objc_release 函数,不会造成内存泄漏
//可以调用被立即释放的对象的实例方法,调用完就被释放

    访问附有 __weak 修饰符的变量时,调用了 objc_loadWeakRetained 函数和objc_autorelease 函数

  1. objc_loadWeakRetained 函数取出附有 __weak 变量所引用的对象并 retain
  2. objc_autorelease 函数将对象注册到 autoreleasepool 中

    在大量使用 __ weak 变量时,注册到 autoreleasepool 中对象也大量增加,最好先暂时赋值给附有 __strong 变量再使用

独自实现引用计数的类大多不支持 __weak,当 allowsWeakReference/retainWeakReference 方法返回 NO 时,也不能使用,该变量将变为 nil

 

__autoreleasing 修饰符

没啥说的,就调用 objc_autorelease 函数
 

引用计数

用 _objc_rootRetainCount 函数获取引用计数值(不完全可信

强引用持有 +1,弱引用不变,向 autoreleasepool 注册+1,访问 __weak +1

上一篇下一篇

猜你喜欢

热点阅读