ARC 并不是 GC(Garbage Collection 垃圾回收器),它只是一种代码静态分析(Static Analyzer)工具,背后的原理是依赖编译器的静态分析能力,通过在编译时找出合理的插入引用计数管理代码,从而提高 iOS 开发人员的开发效率。在编译阶段,编译器将在项目代码中自动为分配对象插入 retain、release 和 autorelease,且插入的代码不可见。
方法群创建的对象的强引用,强引用变量会在其作用域里被保留,在超出作用域后被释放,为默认的修饰符。
- alloc/new/copy/mutableCopy
- //等价
- id obj = [[NSObject alloc] init];
- id __strong obj = [[NSObject alloc] init];
情况下
- alloc/new/copy/mutablecopy
- `alloc`为例的模拟底层代码为:
- id __Strong obj = [[NSObject alloc] init];
- id obj = objc_msgSend(NSobject, @selector(alloc));
- objc_msgSend(obj, @selector(init));
- objc_release(obj);
- 编译器自动帮我们加入了`release`,来释放对象
情况下 array 为例的模拟底层代码为:
- alloc/new/copy/mutablecopy
- id obj = objc_msgSend(NSMutableArray, @selector(array));
- objc_retainAutoreleasedReturnValue(obj);
- objc_release(obj);
array 方法的底层模拟是怎样的呢?是主要用于最优化程序运行
- objc_retainAutoreleasedReturnValue(obj)
- id obj = objc_msgSend(NSmutableArray, @selector(alloc));
- objc_msgSend(obj, @selector(init));
- return objc_autorealeaseReturnValue(obj);
与
- objc_autorealeaseReturnValue(obj)
是成对的,
- objc_retainAutoreleasedReturnValue(obj)
会把对象注册到 autorealeasepool 中,但是如果它检测到方法执行列表中出现
- objc_autorealeaseReturnValue(obj)
方法,那么就不会将返回的对象注册到 autorealeasepool,而是直接传递到方法和函数的调用方。这样直接传递可 以达到最优化。
- objc_retainAutoreleasedReturnValue(obj)
- id __weak obj1 = obj;
- id obj1;
- obj1 = 0;
- objc_storeWeak( & obj1, obj);
- objc_destoryWeak( & obj1);等同于objc_storeWeak( & obj1, 0);
函数将第二个参数的赋值对象的地址作为键值,将第一个参数的附有__weak 修饰符的变量的地址注册到 weak 表中,如果第二个参数为 0,则把变量的地址从 weak 中删除。一个键值可以注册多个变量的地址由此可见,如果大量的 weak 变量,则会消耗 CPU 资源,所以 weak 只用来避免循环引用。
- objc_storeWeak(&obj1,obj)
模拟源码
- id __weak obj1 = obj;
- NSLog(@"%@", obj1);
所以在 autorealeasepool 块结束前可以放心使用 weak 修饰变量。
- id obj1;
- objc_initWeak( & obj1, obj);
- id temp = objc_loadWeakRetained( & obj1);
- objc_autorelease(temp);
- NSLog(@"%@", temp);
- objc_destoryWeak( & obj1);
将对象赋值给附有__autoreleasing 修饰符的变量等同于 ARC 无效时,调用对象的 autorelease 方法。
- @autoreleasepool {
- id __autoreleasing obj = [[NSObject alloc] init];
- }
- // 模拟代码
- id pool = objc_autoreleasePoolPush();
- id obj = objc_msgSend(NSObject, @selector(alloc));
- objc_msgSend(obj, @selector(init));
- objc_autorelease(obj);
- objc_autoreleasPoolPop(pool);
- @autoreleasepool {
- id __autoreleasing obj = [NSMutableArray array];
- }
- // 模拟代码
- id pool = objc_autoreleasePoolPush();
- id obj = objc_msgSend(NSMutableArray, @selector(array));
- objc_retainAutoreleasedReturnValue(obj);
- objc_autorelease(obj);
- objc_autoreleasPoolPop(pool);
- // 虽然 obj 持有对象的方法变为 objc_retainAutoreleasedReturnValue, 但是将 obj 所引用的对象注册到 autoreleasepool 中的方法并没有改变
关于自动释放池的具体实现将会在之后的系列文章中继续探讨
在 ARC 有效时,属性修饰符与所有权修饰符对应使用:
属性声明的属性 | 所有权修饰符 |
---|---|
assign | __unsafe_unretained 修饰符 |
copy | __strong 修饰符(但是赋值的是被复制的对象) |
retain | __strong 修饰符 |
strong | __strong 修饰符 |
unsafe_unretained | __unsafe_unretained 修饰符 |
weak | __weak 修饰符 |
来源: https://juejin.im/post/5a425c85f265da430b7b7fbc