Automatic Reference Counting (ARC) 自动引用计数

来源:互联网 发布:阿里云远程连接不上 编辑:程序博客网 时间:2024/06/06 02:04

http://developer.apple.com/library/mac/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html    

        

         Automatic Reference Counting (ARC)是一个编译器的功能,提供了对Objective-C对象的自动内存管理。ARC在编译期间自动在适当的地方添加Objective-C对象的retainrelease操作代码。


一. 总结

    ARC在编译期间,根据Objective-C对象的存活周期,在适当的位置添加retain和release代码。从概念上讲,ARC与手动引用计数内存管理遵循同样的内存管理规则。ARC也无法防止strong引用循环

    ARC还引入了新的修饰符来修饰变量和声明属性。变量的修饰符__strong,__weak, __unsafe_unretained,__autoreleasing,默认是_strong;声明属性的修饰符strong, weak, unsafe_unretained,默认是strong。

    Objective-C对象和Core Foundation-style对象直接的转换。你需要显示地告诉编译器转换后对象所有权,转换修饰符号:__bridge,__bridge_retained 或 CFBridgingRetain,__bridge_transfer 或 CFBridgingRelease

 ARC支持的系统:Xcode4.2 forOS X v10.6和v10.7(64位应用程序)iOS 4iOS 5weak不支持OS X v10.6和iOS 4。

    Xcode提供一个把手动引用计数转换成ARC的工具,choose Edit > Refactor > Convert to Objective-C ARC。

二.ARC概述

      你不需记住什么时候要用 retain, release, and autorelease,ARC评估你的对象的生命周期,并在编译时自动插入适当的内存管理。编译器还为你生成相应的dealloc方法。

       一个Person类声明如下:

@interface Person : NSObject
@property NSString *firstName;
@property NSString *lastName;
@property NSNumber *yearOfBirth;
@property Person *spouse;
@end
 
@implementation Person
@end
        属性的默认修饰符是strong。

       一个contrived方法如下:

- (void)contrived {
    Person *aPerson = [[Person alloc] init];
    [aPerson setFirstName:@"William"];
    [aPerson setLastName:@"Dudney"];
    [aPerson setYearOfBirth:[[NSNumber alloc] initWithInteger:2011]];
    NSLog(@"aPerson: %@", aPerson);
}
       ARC负责aPerson和NSNumber对象的内存释放。

三.ARC强制执行新规则

      1.不能显示调用 dealloc([super dealloc]), 执行或调用 retain, release, retainCount, or autorelease;禁止使用选择器 @selector(retain), @selector(release), 等。

         你可以实现一个dealloc方法,来释放实例变量以外的资源,例如:系统类调用[systemClassInstance setDelegate:nil]和未使用ARC编译的代码。在dealloc方法中,ARC在适当的地方添加release来负责释放实例变量。

       2.不能使用 NSAllocateObject 和 NSDeallocateObject类。

       3.不能在C结构体中使用对象指针。使用Objective-C类代替C结构体。

       4. id和void*之间要求显示转换。

          使用__bridge,__bridge_retained  CFBridgingRetain__bridge_transfer  CFBridgingRelease来显示转换。

       5.用 @autoreleasepool{}代替NSAutoReleasePool

       6.不能使用memory zones。不再需要NSZone。

       7.实例变量的访问名称不能用new作为前缀,不能声明一个属性用new作为前缀。

      @property NSString *newTitle;//错误
    @property (getter=theNewTitle) NSString *newTitle;//修改访问方法,正确

四.ARC 推出新的对象生命周期修饰符

   1.属性声明修饰符:strong, weak, unsafe_unretained,默认strong

     strongretain相似,只要有一个strong指针指向对象,该对象就不会被销毁;(一个对象,要是没有任何一个strong引用指向该对象,将马上被销毁);

     weak声明为weak的指针,weak指针指向的对象一旦被释放,weak的指针都将被赋值为nil

      unsafe_unretainedunsafe_unretained声明的指针,指针指向的对象一旦被释放,这些指针将成为野指针。

//以下2行代码执行效果一样
@property(retain) MyClass *myObject;
@property(strong) MyClass *myObject;
 
// The following declaration is similar to "@property(assign) MyClass *myObject;"
// except that if the MyClass instance is deallocated,
// the property value is set to nil instead of remaining as a dangling pointer.
@property(weak) MyClass *myObject;
//声明unsafe_unretained属性
@property (nonatomic, strong) NSString *string1;   
@property (nonatomic, unsafe_unretained) NSString *string2;
//执行如下代码后,self.string2成了野指针
self.string1 = [[NSString alloc] initWithUTF8String:"string 1"];   
self.string2 = self.string1;   
self.string1 = nil;  
NSLog(@"String 2 = %@", self.string2);  

      为了避免strong(强引用)循环,parent对象strong(强引用)child对象,child对象weak(弱引用)parent对象。

    2.变量的修饰符__strong,__weak,__unsafe_unretained,__autoreleasing,默认是_strong

       __strong:强引用,只要有一个strong引用指向该对象,那么该对象就不会被销毁;

       __weak:弱引用,不能保持一个对象的存活期,当弱引用指向的对象没有强引用指向时,该弱引用指针被置为nil;

       __unsafe_unretained,__weak相似,只是该引用指针成为野指针。

       __autoreleasing,修饰传递给方法的参数引用(id*),方法返回时自动释放。

       a) 变量定义格式如下:

ClassName * qualifier variableName;
MyClass * __strong myStrongReference;//__strong是默认修饰符,等价于MyClass *myStrongReference;
MyClass * __weak myWeakReference;
MyClass * __unsafe_unretained myUnsafeReference;

//string用NSString对象引用初始化后,由于没有strong引用指向该NSString对象,NSString对象马上就被释放,string被置为nil;

NSString * __weak string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]];
NSLog(@"string: %@", string);//输出null

       b)__autoreleasing,方法的参数是个引用指针(id*):

         参数是个__autoreleasing方法声明如下:

- (BOOL)performOperationWithError:(NSError * __autoreleasing *)error;

NSError *error;   //或定义成 NSError * _autoreleasing error;
BOOL OK = [myObject performOperationWithError:&error];
if (!OK) {
    // Report the error.
    // ...

//编译器自动添加了临时__autoreleasing变量

NSError * __strong error;
NSError * __autoreleasing tmp = error;
BOOL OK = [myObject performOperationWithError:&tmp];
error = tmp;
if (!OK) {
    // Report the error.
    // ...

//返回_autoreleasing定义的变量

-(NSString*)name

{

       _autoreleasing NSString *str = [[NSString alloc] initWithString: @"name"];

       return name;

}


五. ARC编译模式下,iOS和Mac OS X平台对Outlets(用户接口变量) 的管理统一了

     strong: Nib文件所有者(File's Owner)的顶层对象(top-level objects);

     weak:  视图或其他窗口中的Outlets(用户接口变量);


六. ARC编译模式下,堆栈变量初始化为nil。

七. 使用编译器标志启用和禁用ARC

              -fobjc-arc        启用ARC

       -fno-objc-arc     禁用ARC 

    a) ARC编译选项

       项目文件的[Build Settings]->[Apple LLVM compiler4.1 -Language]


    b) 在ARC编译模式下,某些源文件禁用ARC


八. Core fundation style 对象与Objective-C对象的桥接转换(Toll-Free bridge)

     ARC不自动负责Core Foundation-style 对象(例如CFArrayRefCFMutableDictionaryRef、CGColorSpaceRef、 CGGradientRef)的内存释放,你必须使用CFRetain and CFRelease管理Core Foundation-style对象。

      Objective-C对象和Core Foundation-style对象的转换,你需要显式告诉编译器转换后的对象的所有权。

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

     b) __bridge_retainedCFBridgingRetain,Objective-C的对象转换为Core Foundation的对象,同时将对象(内存)的管理权交给我们,后续需要使用CFRelease或者相关方法来释放对象;

     c) __bridge_transferCFBridgingRelease,将Core Foundation的对象转换为Objective-C的对象,同时将对象(内存)的管理权交给ARC。


九. 手动转换项目支持ARC

     a) 不能调用retainrelease,  autorelease.方法;

      b)  不能调用dealloc方法;例如:[super dealloc];

      c)  用@autorelesepool{}代替NSAutoreleasePool;

      d)  init初始化方法, [super init] 改成 self = [super init];

[super init];//错误

self = [super init];//正确
if (self) {
   ...
     e)  没有使用ARC,类的实例变量默认是assign,对象赋值给实例变量,不会改变对象的引用计数;

            使用ARC后,类的实例变量默认是strong,对象赋值给实例变量,会延长对象的存活周期。

     f) 不能在C结构体中使用strong id;

struct X { id x; float y; };//错误

     g)  id和void*(including Core Foundation types)之间不能直接相互转换;

     h)  Nib中的非顶层对象Outlets(用户接口变量),修饰符assign改为weak;

          顶层对象Outlets,修饰符retain改为strong


十. 其他

a)__weak不支持这些类的对象:

     NSATSTypesetterNSColorSpaceNSFontNSMenuViewNSParagraphStyleNSSimpleHorizontalTypesetter, and NSTextView

b) ARC不支持管理的内容: malloc/free分配的对象, Core Foundation-style 对象, file descriptors。

Core Foundation-style 对象,它是由C的struct定义的各种对象,主要来自于CoreFoundation框架(如CFArray或者CFMutableDictionaryRef类型),或者其它采用CoreFoundation命名规范的框架,如Core Graphics(如,CGColorSpaceRef 和CGGradientRef)。