0%

Objective-C内存管理之所有权修饰符

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方法.