__strong 修饰符: 持有强引用的变量在超出其作用域时被废弃, 随着强引用的失效, 引用的对象会随之释放
__strong 修饰符是 id 类型和对象类型默认的所有权修饰符.
id 和对象类型在没有明确指定所有权修饰符时, 默认为 __strong 修饰符.
id obj = [[NSObject alloc] init];
=>
ARC有效时:
id __strong obj = [[NSObject alloc] init];
ARC无效时:
{
id __strong obj = [[NSObject alloc] init];
}
__weak 弱引用修饰符: 不能持有对象实例. 在持有某对象的弱引用时, 若该对象被废弃, 则此弱引用将自动失效且处于 nil 被赋值的状态
循环引用容易发生内存泄漏.
内存泄漏: 应当废弃的对象在超出其生存周期后继续存在.
__ussafe_unretained 修饰符: 不安全的所有权修饰符
附有 __unsafe_unretained 修饰符的变量不属于编译器的内存管理对象
__autoreleasing 修饰符:
编译器会检查方法名是否以 alloc/new/copy/mutableCopy 开始, 如果不是则自动将返回值的对象注册到 autoreleasepool
访问附有 __weak 修饰符的变量时, 实际上必定要访问注册到 autoreleasepool 的对象. 因为要保证在此区域中对象存在
id __weak obj1 = obj0;
NSLog(@"class=%@", [obj1 class]);
以下源代码与此相同.
id __weak obj1 = obj0;
id __autoreleasing tmp = obj1;
NSLog(@"class=%@", [tmp class]);
因为 __weak 修饰符只持有对象的弱引用, 而在访问引用对象的过程中, 该对象有可能被废弃. 如果把要访问的对象注册到 autoreleasepool 中, 那么在 @autoreleasepool 块结束之前都能确保该对象存在. 因此, 在使用附有 __weak 修饰符的变量时就必定要使用注册到 autoreleasepool 中的对象.
id 的指针或对象的指针在没有显式指定时会被附加上 __autoreleasing 修饰符
- (BOOL) performOperationWithError:(NSError **)error;
=>
- (BOOL) performOperationWithError:(NSError * __autoreleasing *)error;
参数中持有 NSError 对象指针的方法, 虽然为响应其执行结果, 需要生成 NSError 类对象, 但也必须符合内存管理的思考方式.
作为 alloc/new/copy/mutableCopy 方法返回值取得的对象是自己生成并持有的, 其他情况下便是取得非自己生成并持有的对象. 因此, 使用附有 __autoreleasing 修饰符的变量作为对象取得参数, 与除 alloc/new/copy/mutableCopy 外其他方法的返回值取得对象完全一样, 都会注册到 autoreleasepool, 并取得非自己生成并持有的对象
赋值给对象指针时, 所有权修饰符必须一致.
NSError *error = nil;
NSError **pError = &error;
产生编译错误
修正:
NSError *error = nil;
NSError * __strong *pError = &error;
前面的不同修饰符没有报错, 是因为编译器自动地将源代码转化成了下面形式.
NSError __strong *error = nil;
NSError __autoreleasing *tmp = error;
BOOL result = [obj performOperationWithError:&tmp];
error = tmp;
__strong/__weak/__autoreleasing 修饰符可以保证将附有这些修饰符的自动变量初始化为nil.
id __strong obj0;
id __weak obj1;
id __autoreleasing obj2;
=>
id __strong obj0 = nil;
id __weak obj1 = nil;
id __autoreleasing obj2 = nil;