iOS中的ARC---ARC规则

本文参考:《objective-c高级编程》

一、什么是ARC

简单来归纳:
①ARC的本质也是引用计数在管理内存,ARC只是自动帮助处理引用计数。
②引用计数的机制就是如果没有强引用指向对象,对象就会被释放。
③ARC中所有权的修饰符包括:__strong、__weak、__unsafe_unretained、__autoreleasing

二、使用ARC

①使用clang(LLVM编译器)3.0或者以上的版本
②指定编译器属性为“-fobjc-arc”(取消arc为“-fno-obj-arc”)。
实际使用中工程支持ARC,但是有些导入文件可能不支持ARC,此时只要在Building Phrases—>Compile Sources中找到对应的实现文件,按以上方法更改属性即可。

三、修饰符的详细说明

1.__strong:如果没有明确指明,默认为__strong

ARC中代码:

//取得自己生成并持有的对象
{
    id __strong obj = [[NSObject alloc] init];
}

//取得非自己生成并持有的对象
{
    id __strong obj = [NSMutableArray array];
}   

非ARC中实现:

{
    id obj = [[NSObject alloc] init];
    [obj release];
}

{
    id obj = [NSMutableArray array];
    [obj retain];
    [obj release];
}   

②__weak:很好的解决了强引用中的“循环引用”的问题

PS:什么是循环引用?
a)有一个test类,它又一个id __strong _obj属性成员。
b)test1,test2实例对象分别生成并持有了A、B对象,但是test1中调用并持有了test2,test2中也调用并持有了test1。
c)当超出test1和test2的作用域时,强引用失效,test1、test2实例对象分别要释放A、B对象。但是,test1中还持有了B对象,test2中还持有了A对象,造成循环引用,内存泄露。(也可以理解为,test1执行release方法时需要等待它持有的B对象释放,test2也要等A对象释放,此时造成了相互等待,即两块内存都没有释放,内存泄露)

所以就有了__weak,它不能持有对象实例。当它指向的对象不存在强引用时,它就会被释放,而且自动被置为nil。

PS:__weak在runtime中是如何实现自动置为nil的呢?
runtime 对注册的类, 会进行布局,对于 weak 对象会放入一个 hash 表中。 用 weak 指向的对象内存地址作为 key,当此对象的引用计数为0的时候会 dealloc,假如 weak 指向的对象内存地址是a,那么就会以a为键, 在这个 weak 表中搜索,找到所有以a为键的 weak 对象,从而设置为 nil。

③__unsafe_unretained:和__weak功能相同,但是没有自动设置nil的功能。在iOS4以及OS X Snow Leopard的应用程序中使用。
当程序员没有手动设置nil值的时候,程序就会崩溃。类似C语言中常用的ASSERT调试手段一样的功能。

④__autoreleasing:虽然ARC中不能使用autorelease修饰符,也不能使用NSAutoreleasePool类。但是autorelease在ARC中还是起了作用的。

我们知道ARC无效时,NSAutoreleasePool类就像C语言中的作用域“{}”一样为我们制定了一个使用autorelease的范围。
但是在ARC中,指定”@autoreleasepool块”来代替NSAutoreleasePool类、指定”__autoreleasing”代替autorelease,即

@autoreleasepool{
    id __autoreleasing obj = [[NSObject alloc] init];   
}

四、显示的使用__autoreleasing和显示的使用__strong都是非常罕见的。(单独作为一个版块讲解)

1.由于return使得对象变量超出其作用域,所以该强引用对应的自己持有的对象会被自动释放。(显然不能是这样的)
所以编译器对于返回值做了处理,自动注册到autoreleasepool

+(id) array 
{
    return [[NSMutableArray alloc] init];
}

2.访问__weak修饰的变量,它首先必定要被注册到autoreleasepool
原因:__weak修饰的对象是弱引用,在访问的过程中随时有可能被废弃。所以编译器把它注册到autoreleasepool中,确保不会出错

id __weak obj1 = obj0;
NSLog(@"class = %@", [obj1 class]);

//编译器内部实际上做了处理
id __weak obj1 = obj0;
id __autoreleasing tmp = obj1;
NSLog(@"class = %@", [tmp class]);

3.id的指针默认是被__autoreleasing修饰的(就好比id对象和其他对象默认是被__strong修饰的一样)

①首先,我们要知道一点:赋值给对象指针时,所有权修饰符必须一致

NSError *error = nil;
NSError **pError = &error;  //wrong
NSError __strong **pError = &error;  //right

②所以在使用id指针的时候,其实编译器还是帮了我们大忙的

NSError __strong *error = nil;
BOOL result = [obj performOperationWithError:&error];

//以上代码的实际操作
NSError __strong *error = nil;
NSError __autoreleasing *tmp = error;
BOOL result = [obj performOperationWithError:&tmp];
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值