Objc中的对象类型就是指向NSObjec类或其子类的指针, 例如NSObject *
. id类型用于隐藏对象类型的类名部分, 相当于C语言中的void *
.
ARC有效时, id类型和对象类型必须附加所有权修饰符. 所有权修饰符一共有4种:
- __strong修饰符
- __weak修饰符
- __unsafe_unretained修饰符
- __autoreleasing修饰符
__strong修饰符
__strong修饰符是id类型和对象类型默认的所有权修饰符. 也就是说, 下面代码中的id变量, 实际上被附加了所有权修饰符.
id obj = [[NSObject alloc]init];
等同于:
id __strong obj = [[NSObject alloc]init];
在ARC无效时, 上面的代码等同于:
// ARC无效时
{
id obj = [[NSObject alloc]init];
[obj release];
}
__strong修饰符表示对对象的”强引用”, 由__strong修饰的变量在超出作用域, 即在该变量被废弃时, 随着强引用的失效, 会释放被其修饰的变量.
__weak修饰符
如果只是使用__strong修饰符的话并不能处理”循环引用”的情况. 因此需要引入__weak修饰符.
__weak修饰符提供弱引用, 弱引用不能持有对象实例.
id __weak obj = [[NSObject alloc]init];
如果编译上面的代码, 编译器会发出警告. 因为obj为弱引用, 生成的对象会被立即释放.
__weak修饰符还有一个优点, 在持有某个对象的弱引用时, 若该对象被废弃, 则次弱引用将自动失效且被赋值为nil.
__weak修饰符只能用于iOS5以上版本. 在iOS5以前, 可以使用
__unsafe_unretained修饰符.
__unsafe_unretained修饰符
__unsafe_unretained修饰符是不安全的所有权修饰符. 附有__unsafe_unretained修饰符的变量不属于编译器的内存管理对象.
id __unsafe_unretained obj = [[NSObject alloc]init];
该代码将自己生成并持有的对象赋值给附有__unsafe_unretained修饰符的变量. 同__weak一样, 编译器会给出警告. 因为附有__unsafe_unretained修饰符的变量和附有__weak修饰符的变量一样, 不会持有生成的对象, 所有生成的对象会被立即释放. 到这里, __unsafe_unretained和__weak是一样的.
再看下面的代码:
id __unsafe_unretained obj1 = nil;
{
id __strong obj0 = [[NSObject alloc]init];
//obj1既不持有对象的强引用,也不持有对象的弱引用
obj1 = obj0;
NSLog(@"In: %@",obj1);
}
//obj0超出作用域, 被废弃
//此时obj1访问了被废弃的对象(野指针), 可能会引起崩溃
NSLog(@"Out: %@",obj1);
在使用__unsafe_unretained修饰符对象时, 必须保证对象确实存在, 否则可能会引起崩溃.
__autoreleasing
ARC有效时不能使用autorelease方法, 也不能使用NSAutoreleasePool类.
但是可以使用@autoreleasepool
块来替代NSAutoreleasePool, 使用__autoreleasing修饰变量来替代调用autorelease方法.