ARC 定义
ARC (Automatic Reference Counting) 是指内存管理中采用自动引用计数, iOS 中 LLVM 编译器设置 ARC 为有效状态时, 就不需再手动插入 retain 和 release
什么是引用计数
引用计数是管理对象生命周期的一种方式, 创建对象的时候, 引用计数为1, 有一个新的指针指向这个对象的时候, 引用计数 +1, 当这个新指针不再指向这个对象的时候, 引用计数 -1, 当引用计数为 0 的时候, 可以将对象销毁, 回收内存
ARC 规则
-
设置 ARC 有效
- LLVM 编译器 版本 >= 3.0 (Xcode 4.2 之后的版本)
- 指定编译器属性为 -fobjc-arc
-
关闭 ARC
- 指定编译器属性为 -fno-objc-arc
-
所有权修饰符
- __strong : id 类型和对象类型的默认所有权修饰符
- 自己生成的对象, 自己持有
- 非自己生成的对象, 自己也能持有
- 不再需要自己持有的对象时释放
- 非自己持有的对象无法释放
- __strong : id 类型和对象类型的默认所有权修饰符
- __weak:弱引用
- __unsafe_unretained : 不属于编译器内存管理的对象
- __autoreleasing :
- 编译器会检查方法名是否以 alloc/ new / copy / mutableCopy 开始, 如果不是则自动将对象注册到 autoreleasepool
- 对象作为函数的返回值, 编译器会自动将其注册到 autoreleasepool
- 使用 __weak 修饰的变量, 就要使用注册到 autoreleasepool 中的对象, 确保对象存在
id __weak obj1 = obj0; id __autoreleasing tmp = obj1;
- id 的指针或者对象的指针在没有显示指定时, 会被附加上 __autoreleasing 修饰符
- 赋值给对象指针时, 所有权修饰符必须一致
// 报错 NSError *error = nil; NSError **pError = &error; // 正确 NSError *error = nil; NSError * __strong *error = &error;
- 函数带有 __autorelease 参数的优化, 所有权不同但是不会由警告
- (BOOL)executeError:(NSError * __autoreleasing *) error; NSError __strong * error = nil; [self executeError: &error]; | | 自动转换成下面的调用 | | NSError __strong *error = nil; NSError __autoreleasing *tmp = error; [self executeError:&tmp];
⚠️ 所遵循的规则
- 不能使用 retain / release / retainCount / autorelease
- 不能使用 NSAllocateObject / NSDeallocateObject
- 遵循内存管理方法命名规则
- alloc / new / copy / mutableCopy 开头的方法必须返回调用方所持有的对象
- ARC 有效的情况下 init 开头的方法也必须返回对象
- 不显示调用 dealloc
- 使用 @autoreleasepool 代替 NSAutoreleasePool
- 不能使用 NSZone
- 对象变量不能作为 C 语言的结构体成员
- 显示转换 id 和 void *
__bridge 、__bridge_retain 、 __bridge_transfer
- __bridge: CF 和 OC 对象转化时只涉及对象类型不涉及对象所有权的转化
- __bridge_retain : OC 对象转换成 CF 对象时, 将 OC 对象所有权交给 CF 对象来管理
- __bridge_transfer: CF 对象转成 OC 对象时, 将 CF 对象的所有权交给 OC , ARC 能自动管理内存
ARC 实现
__strong
// 调用 alloc / new / copy / mutableCopy 方法
id __strong obj = [NSObject alloc] init];
| |
| |
id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init));
objc_release(obj);
// 调用其他方法
id __strong obj = [NSMutableArray array];
| |
| |
id obj = objc_msgSend(NSMutableArray, @selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_release(obj);
__weak
- 从 weak 表中获取废弃对象的地址为键值记录
- 把 __weak 修饰符变量的地址全部置为 nil
- 从 weak 表中删除记录
- 从引用计数表中删除废弃对象的地址为键值得记录
alloc
底层调用了 calloc
dealloc
- _objc_rootDealloc
- rootDealloc
- object_dispose
- objc_destructInstance
- clear_deallocating
网友评论