什么是arc?

作者: IreneWu | 来源:发表于2016-08-25 10:48 被阅读573次

    Automatic Reference Counting,自动引用计数,即ARC,WWDC2011和iOS5所引入的。ARC是新的LLVM 3.0编译器的一项特性,使用ARC,解决了手动内存管理的麻烦。永远不写retain,release和autorelease三个关键字。

    当ARC开启时,编译器将自动在代码合适的地方插入retain,release和autorelease。

    关于效率:ARC是Objective-C编译器的特性,而不是运行时特性或者垃圾回收机制,ARC所做的只不过是在代码编译时为你自动在合适的位置插入release或autorelease,就如同之前MRC时你所做的那样。因此,至少在效率上ARC机制是不会比MRC弱的,而因为可以在最合适的地方完成引用计数的维护,以及部分优化,使用ARC甚至能比MRC取得更高的运行效率。

    ARC的基本规则:只要某个对象被任一strong指针指向,那么它将不会被销毁。如果对象没有被任何strong指针指向,那么就将被销毁。weak类型的指针也可以指向对象,但是并不会持有该对象。

    使用ARC以后,不论是strong还是weak类型的指针,都不再会指向一个dealloced的对象,从根源上解决了意外释放导致的crash

    __weak NSString *str = [[NSString alloc] initWithFormat:…];

    NSLog(@"%@",str); //输出是"(null)"

    由于str是weak,它不会持有alloc出来的NSString对象,因此这个对象由于没有有效的strong指针指向,所以在生成的同时就被销毁了。如果我们在Xcode中写了上面的代码,我们应该会得到一个警告,因为无论何时这种情况似乎都是不太可能出现的。你可以把weak换成strong来消除警告,或者直接前面什么都不写,因为ARC中默认的指针类型就是strong。

    编译标记:-fno-objc-arc和-fno-objc-arc

    除了最顶层的IBOutlet意外,自己写的outlet都应该是weak)。通过加载xib得到的用户界面,在其从xib文件加载时,就已经是view hierarchy的一部分了,而view hierarchy中的指向都是strong的。因此outlet所指向的UI对象不应当再被hold一次了。将这些outlet写为weak的最显而易见的好处是你就不用再viewDidUnload方法中再将这些outlet设为nil了

    总结一下新加入的property的关键字类型:

    strong 和原来的retain比较相似,strong的property将对应__strong的指针,它将持有所指向的对象

    weak 不持有所指向的对象,而且当所指对象销毁时能将自己置为nil,基本所有的outlet都应该用weak

    unsafe_unretained 这就是原来的assign。当需要支持iOS4时需要用到这个关键字

    copy 和原来基本一样..copy一个对象并且为其创建一个strong指针

    assign 对于对象来说应该永远不用assign了,实在需要的话应该用unsafe_unretained代替(基本找不到这种时候,大部分assign应该都被weak替代)。但是对于基本类型比如int,float,BOOL这样的东西,还是要用assign。

    那么ARC是为了解决什么问题诞生的呢?这个得追溯到MRC手动内存管理时代说起。

    MRC下内存管理的缺点:

    1.当我们要释放一个堆内存时,首先要确定指向这个堆空间的指针都被release了。(避免提前释放)

    2.释放指针指向的堆空间,首先要确定哪些指针指向同一个堆,这些指针只能释放一次。(MRC下即谁创建,谁释放,避免重复释放)

    3.模块化操作时,对象可能被多个模块创建和使用,不能确定最后由谁去释放。

    4.多线程操作时,不确定哪个线程最后使用完毕

    桥接一般用于Objective-C的对象与Core Foundation中的类对象之间的转换。它实际上是内存储管理权的移交。因为Objective-C是ARC管理的对象,而Core Foundation不是ARC管理的对象,所以才要特意这样转换。也就是说,当这两种类型(有ARC管理,没有ARC管理)在转换时,需要告诉编译器怎样处理对象的所有权。

    (1)__bridge:只做类型转换,但是不修改对象(内存)管理权

    NSString *string = [NSString stringWithFormat:...];

    CFStringRef cfString = (__bridge CFStringRef)string;

    说明:__bridge只是单纯地执行了类型转换,没有进行所有权的转移,也就是说,当string对象被释放的时候,cfString也不能被使用了。

    (2)__bridge_retained /CFBridgingRetain:将Objective-C的对象——>Core Foundation的对象,同时将对象(内存)的管理权交给开发者,后续需要使用CFRelease或者相关方法来释放对象

    NSString *string = [NSString stringWithFormat:...];

    CFStringRef cfString = (__bridge_retained CFStringRef)string;

    ...

    CFRelease(cfString); // 由于Core Foundation的对象不属于ARC的管理范畴,所以需要自己release

    说明:__bridge_retained 可以通过转换目标处(cfString)的 retain 处理,来使所有权转移。即使 string 变量被释放,cfString 还是可以使用具体的对象。只是有一点,由于Core Foundation的对象不属于ARC的管理范畴,所以需要自己release。可以用 CFBridgingRetain 替代 __bridge_retained 关键字:

    NSString *string = [NSString stringWithFormat:...];

    CFStringRef cfString = CFBridgingRetain(string);

    ...

    CFRelease(cfString); // 由于Core Foundation不在ARC管理范围内,所以需要主动release

    (3)__bridge_transfer/CFBridgingRelease:将Core Foundation的对象——>Objective-C的对象,同时将CF对象(内存)的管理权交给ARC,不需要手动release

    CFStringRef cfString = CFStringCreate...();

    NSString *string = (__bridge_transfer NSString *)cfString;

    // CFRelease(cfString); 因为已经用 __bridge_transfer 转移了对象的所有权,所以不需要调用 release

    同样,我们可以使用 CFBridgingRelease() 来代替 __bridge_transfer 关键字:

    CFStringRef cfString = CFStringCreate...();

    NSString *string = CFBridgingRelease(cfString);

    相关文章

      网友评论

        本文标题:什么是arc?

        本文链接:https://www.haomeiwen.com/subject/ejzosttx.html