zoukankan      html  css  js  c++  java
  • ios5 ARC机制介绍和使用

    参考http://www.yifeiyang.net/development-of-the-iphone-simply-1/

       http://blog.csdn.net/diyagoanyhacker/article/details/7069889

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

    Xcode4.2 创建项目时候会让你选择是否使用"Use Automatic Reference Counting"机制  (使用自动引用计数)

    ARC 简介

    ARC是iOS 5推出的新功能,全称叫 ARC(Automatic Reference Counting)。

     自动引用计数(ARC),是一项为Objective - C程序在编译时提供自动内存管理的功能。ARC可以让你把注意力集中在你感兴趣的代码,对象图,和你的应用程序中的对象之间的关系,让你不必再花费精力在retain和release操作上。正如下图所示,ARC可以减少开发中的内存管理步骤,简化开发。

    简单地说,就是代码中自动加入了retain/release,原先需要手动添加的用来处理内存管理的引用计数的代码可以自动地由编译器完成了。

    该机能在 iOS 5/ Mac OS X 10.7 开始导入,利用 Xcode4.2 可以使用该机能,ARC支持Mac OS X v10.6/10.7 (64-bit applications) 上的Xcode 4.2,支持iOS4、iOS5。但是ARC在Mac OS X v10.6和iOS4上,不支持Weak references(弱引用)。

    简单地理解ARC,就是通过指定的语法,让编译器(LLVM 3.0)在编译代码时,自动生成实例的引用计数管理部分代码。有一点,ARC并不是GC,它只是一种代码静态分析(Static Analyzer)工具。

    Xcode中加入了一个新的工具,用于自动处理ARC里机械式的操作,如移出项目代码中的retain和release方法 调用),而且它还可以帮你修订那些不能自动移植的代码。这个代码移植工具,支持转化项目中的所有代码为ARC模式,如果觉得不方便,你也可以选择手动方式来处理这些文件。但是要在Build Settings中进行设置。

    1. 一个完整、正确的,用来描述“Person”特性的类的实现(implementation),是这样的:

    Person.h文件

    @interface Person : NSObject

    @property (nonatomic, strong) NSString *firstName;

    @property (nonatomic, strong) NSString *lastName;

    @property (nonatomic, strong) NSNumber *yearOfBirth;

    @property (nonatomic, strong) Person *spouse;

    @end

    Person.m文件

    @implementation Person

    @synthesize firstName, lastName, yearOfBirth, spouse;

     

    @end

    ( strong 属性的描述参见 “ARC Introduces New Lifetime Qualifiers”.)
    2. 使用ARC的话,你可以实现一个人为的方法,如下:

    - (void)contrived {    

         Person *aPerson = [[Person alloc] init];   

         [aPerson setFirstName:@"William"];    

         [aPerson setLastName:@"Dudney"];    

         [aPerson:setYearOfBirth:[[NSNumber alloc] initWithInteger:2011]];    

         NSLog(@"aPerson: %@", aPerson);

    }

    因为使用ARC来管理内存,所以无论是“Person”或者“NSNumber”都不会发生内存泄漏。


    你也可以像这样更安全的执行“Person”的“takeLastNameFrom: ”方法:

    - (void)takeLastNameFrom:(Person *)person {   

       NSString *oldLastname = [self lastName];   

       [self setLastName:[person lastName]];    

      NSLog(@"Lastname changed from %@ to %@", oldLastname, [self lastName]);

    }

    ARC在NSLog方法调用之前是不会释放oldLastName的。

    使用ARC必须遵守的新规则


    为了正常运行,ARC引入了一些特有的新规则。新规则的用于提供一个完整可靠的内存管理模式;这些规则有些是用于更好的用户体验,另外一些则是用于简化你的编码,或让你不必再为内存管理操心。如果你违反了这些规则,在你编译的时候就会报错了,而不是当你编译成功,开始运行时出现一些bug。

    1.不可以再显示调用dealloc、或实现调用retain、release、retainCount、autorelease这些方法。


    2.很明显也不能使用@selector(retain), @selector(release),等等。


    3.当你需要管理一些非实例变量的资源时,你可以实现一个dealloc方法。你不需要也不能去释放实例变量,

       但您可以调用[systemClassInstance setDelegate:nil]或不使用ARC编译的内存管理代码。


    4. 在ARC下去自定义dealloc方法不需要调用 [super dealloc],(实际上如果你调用了 [super dealloc],编译器会报错)。

        super的调用是由编译器自动强制执行的。


    5. CFRetain, CFRelease, 还有其他Core Foundation-style objects函数 (详见“Managing Toll-Free Bridging”)还是可以执行的。

    6. 不能使用NSAllocateObject或NSDeallocateObject。

    7. 使用alloc来创建对象,由ARC来管理对象运行时的释放。

    8. 不能在C语言的结构体中使用对象指针。

    9. 建议使用Objective-C的class来管理数据格式,来代替C语言的struct。

    10.不能隐式转换 id和void *。

    11.你必须告诉编译器转换的类型。当你需要在obj-C的对象和Core Foundation 类型之间转换时,你可以通过函数的参数来做。详见“Managing Toll-Free Bridging”。

    12.不能使用NSAutoreleasePool对象。ARC提供了一个@autoreleasepool块来代替,这个块相比NSAutoreleasePool来说,具有更高的有效性。

    13. 不能使用memory Zone。因为现在Objective-C运行时已经忽略NSZone了,所以没必要再使用NSZone了。


    14.为了可以和手动内存管理(manual retain-release)的代码兼容,ARC提出了一些变量方法的命名规约。
    15.你不能用“new”来做property的名字开头。

    ARC引入的新的生命周期修饰符
    ARC引入了一些新的生命周期修饰符和zeroing weak引用.。一个weak引用不会改变它所指向对象的生命周期。 一个zeroing weak引用会在它指向的对象被释放以后,自动赋为nil。


    在你的程序中,你应该灵活运用修饰符来管理你的对象图。特别是,ARC不会去保护strong引用的retain周期(详见“Practical Memory Management”),所以谨慎使用weak可以确保你不会创建循环引用。

    Property 属性
    在下面的几个例子中,我们介绍一下新的property属性关键词weak、strong。

    // 下面的声明: @property(retain) MyClass *myObject;和@property(strong) MyClass *myObject;是一样的

    // 下面的声明和 "@property(assign) MyClass *myObject;"和@property(weak) MyClass *myObject;是相似的, 但是,当 MyClass 被释放的时候,值被设为nil,而不是一个空指针。

     

    变量修饰符

    你可以用下面的生命周期修饰符来声明变量,就像你使用const一样

    __strong
    __weak
    __unsafe_unretained
    __autoreleasing

     __strong是默认的修饰符。

    __weak修饰了一个自动nil的weak引用。

    __unsafe_unretained声明了一个不会自动nil的weak引用。当变量被释放,那么它就变成了一个空指针了。

    __autoreleasing 用来修饰一个声明为 (id *)的函数的参数,当函数返回值时被释放。

     当你用__weak来修饰栈上的变量时,你必须格外小心。参考下面的例子

    NSString __weak *string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]];

    NSLog(@"string: %@", string);

    虽然string在分配空间并初始化后就被赋值,但是没有别的strong引用对象指向string,所以string被立刻释放了。很明显,NSLog显示出的string值是nil、

    同样,你需要在对象值传递时格外注意。下面的代码是可以执行的:

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

    However, the error declaration is implicitly:但是,error的声明是隐式的:NSError *_strong e = nil;

     

    而函数声明是这样的:

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

     那么,编译器会重写代码,变成:

      1. NSError __strong *error = nil;
      2. NSError __autoreleasing *tmp = error;
      3. BOOL OK = [myObject performOperationWithError:&tmp];
      4. error = tmp;if (!OK) {    // Report the error.    // ...当本地变量声明(__strong *error)和函数的参数((NSError * __autoreleasing *)error)不匹配的时候,编译器会创建一个临时变量。当你获得一个__strong变量的地址时,你可以初始化一个id __strong *的指针来声明 ,这样你就可以获得指针的原型,或者你可以声明一个变量为__autoreleasing。
      5.  

     使用生命周期修饰符来避免Strong引用周期
    你 可以使用生命周期修饰符来避免Strong引用周期。例如,当你制作了一组父子结构的对象,而且父类要引用子类,则会出现Strong引用周期;反之,当 你将一个父类指向子类为strong引用,子类指向父类为weak引用,就可以避免出现Strong引用周期。当对象包含block objects时,这样的情况会变的更加隐性。
    在 手动内存管理模式下, __block id x; 控制x内存计数增加。 在ARC模式下,__block id x默认对x内存技术增加。为了使手动内存管理模式代码可以在ARC模式下正常工作, 你可以用__unsafe_unretained来修饰__block id x;。就和“__unsafe_unretained”字面上的意思一样,;然而,这样一个non-retained变量是危险的(因为它会变成一个野指 针) 会带来不良后果。有两种更好一点的方法来处理,一是使用__weak (当你不需要支持iOS 4或OS X v10.6), 二是设__block值为nil,结束他的生命周期。
    下面是手动内存管理的代码,说明了这个问题,

    MyViewController *myController = [[MyViewController alloc] init];

    myController.completionHandler =  ^(NSInteger result) { 

      [myController dismissViewControllerAnimated:YES completion:nil];

    };

    [self presentViewController:myController animated:YES completion:^{  [myController release];}];


    如上所述,相反,你可以使用 __block修饰符然后设置myController的值为nil:

    __block MyViewController *myController = [[MyViewController alloc] init…];// ...

    myController.completionHandler =  ^(NSInteger result) {   

     [myController dismissViewControllerAnimated:YES completion:nil];    myController = nil;

    };

    另外,你还可以使用一个临时__weak变量。下面的例子下面的例子说明了一个简单的实现:

    1. MyViewController *myController = [[MyViewController alloc] init…];// ...
    2. __weak MyViewController *weakMyViewController = myController;myController.completionHandler =  ^(NSInteger result) {  
    3.   [weakMyViewController dismissViewControllerAnimated:YES completion:nil];
    4. };

    对于一般情况,你可以这样来做:

    MyViewController *myController = [[MyViewController alloc] init…];// ...

    __weak MyViewController *weakMyController = myController;myController.completionHandler =  ^(NSInteger result){   

     MyViewController *strongMyController = weakMyController;  

        if (strongMyController) {        // ...       

         [strongMyController dismissViewControllerAnimated:YES completion:nil];        // ...   

       }    else {        //

         Probably nothing...    

      }

    };

    在某些情况下,比如类不支持__weak模式时,你可以使用__unsafe_unretained。但是,很难保证正确的生命周期,能难或者说不可能去验证一个__unsafe_unretained指针是否有效。

    ARC提供一个新的声明来管理Autorelease Pools
    使用ARC,你不能再使用NSAutoReleasePool类来直接管理autorelease pools。取而代之,ARC提供了一个新的Objective-C语法来代替。

    @autoreleasepool {     // Code, such as a loop that creates a large number of temporary objects.}

    通过上面的新语法,可以编译器管理autorelease pools的状态。
    在 这个@autoreleasepool入口,autorelease pool会压入栈中,当正常退出的时候(break, return, goto, fall-through等),autorelease pool 会出栈,但是当出口代码不兼容,异常退出autorelease pool,则autorelease pool 就不会出栈。
    这个语法在所有的Objective-C模式下都能工作。它比NSAutoReleasePool更有效率。建议你把原先的所有NSAutoReleasePool代码都改成新的模式。

    Patterns for Managing Outlets Become Consistent Across Platforms
    在被ARC处理过的iOS和OS X中,声明的outlets将会趋于统一。

    一般来说outlets变量被修饰为weak,但是如果outlets变量的所有者是nib文件中的top-level对象(或者是storyboard scene)时,应被修饰为strong。

    详细参考Resource Programming Guide中的“Nib Files”

    栈变量必须初始化为nil
    使用ARC模式,strong,weak,autoreleasing栈变量都被隐式的初始化为nil,例如:

    - (void)myMethod {    NSString *name;    NSLog(@"name: %@", name);}

    运行是程序不会崩溃,NSLog会打印出“null”。

    使用编译标识来开关ARC模式
    你可以使用 -fobjc-arc来启用ARC。你也可以使用-fno-objc-arc来为某个你希望使用手动管理内存的文件来禁用ARC。
    Xcode4.2再MAC OS X10.6和10.7(64位应用)和iOS 4,iOS5支持ARC,Mac OS X 10.6和iOS4不支持weak引用,Xcode4.1以及以前的版本不支持ARC。
    你 也可以用在一个逐文件处理的方法中使用ARC来手动处理某些文件。For projects that employ ARC as the default approach, you can disable ARC for a specific file using a new-fno-objc-arc compiler flag for that file.

    管理 Toll-Free Bridging
    在许多的cocoa应用中,你需要用到Core Foundation类型,无论是来自Core Foundation framework本身 (例如CFArrayRefCFMutableDictionaryRef)或是由Core Foundation扩展出的framework,例如Core Graphics (例如CGColorSpaceRefCGGradientRef).
    编译器不会自动管理Core Foundation对象的生命周期;你必须使用CFRetainCFRelease (或相应的特殊类型的变量) 来符合Core Foundation内存管理规则 (详见Memory Management Programming Guide for Core Foundation).
    如 果你在Objective-C和Core Foundation-style类型对象之间转换, 你需要用一个转换(定义在inobjc/runtime.h)或一个Core Foundation-style的宏(定义在NSObject.h),来告诉编译器这个对象的所属关系:
    如果你倾向与用函数调用,你可以用宏例如CFBridgingRetain。这个宏使用新的方法将id和void* 之间转换,并告诉编译器关于这个void*的内存计数器的值。

    NS_INLINE CFTypeRef CFBridgingRetain(id X) {    return (__bridge_retain CFTypeRef)X;} NS_INLINE id CFBridgingRelease(CFTypeRef X) {    return (__bridge_transfer id)X;}

    需要使用(__bridge)。
    如果你喜欢C语言式样的转换,你可以直接使用转换:

    id my_id;CFStringRef my_cfref;...NSString   *a = (__bridge NSString*)my_cfref;     //

    Noop cast.CFStringRef b = (__bridge CFStringRef)my_id;      // Noop

    cast....NSString   *c = (__bridge_transfer NSString*)my_cfref; // -1 on the

    CFRefCFStringRef d = (__bridge_retained CFStringRef)my_id;  // returned CFRef is +1

    编译器处理从CF Objects返回的Cocoa方法

    编译器理解遵从Core Foundation返回的Cocoa命名转换Objective-C方法,(详见Advanced Memory Management Programming Guide)。例如,编译器知道,在iOS里,CGColor返回的CGColor不属于UIColor。下面的方法来说明:

    - (id)initWithCoder:(NSCoder *)aDecoder {   

       self = [super initWithCoder:aDecoder];  

       if (self) {        

        CAGradientLayer *gradientLayer = (CAGradientLayer *)[self layer];       

          gradientLayer.colors = [NSArray arrayWithObjects:[[UIColodarkGrayColor]CGColor],                                                        

            [[UIColor lightGrayColor] CGColor], nil];       

        gradientLayer.startPoint = CGPointMake(0.0, 0.0);        

        gradientLayer.endPoint = CGPointMake(1.0, 1.0);    

       }   

       return self;

    }

    转换函数的参数使用所属关系关键字
    当你用转换Objective-C和Core Foundation对象类型的时候, 你需要去告诉编译器这个传入的参数的所属关系。Core Foundation对象的所属关系规则定义在Core Foundation memory management rules中(详见Memory Management Programming Guide for Core Foundation);Objective-C对象规则定义在Advanced Memory Management Programming Guide中。
    下面所示代码中,传入CGGradientCreateWithColors函数的数组需要进行转换。所返回的对象从属关系arrayWithObjects: 没有被传入函数中,转换使用了关键字__bridge。

    NSArray *colors = [NSArray arrayWithObjects:[[UIColor darkGrayColor] CGColor],                                          

     [[UIColor lightGrayColor] CGColor], nil];

    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations);


    下面的代码演示了,注意所有核心内存管理函数都是遵循基础核心内存管理规则的:

    - (void)drawRect:(CGRect)rect {   

       CGContextRef ctx = UIGraphicsGetCurrentContext();   

       CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();  

         CGFloat locations[2] = {0.0, 1.0};  

         NSArray *colors = [NSArray arrayWithObjects:[[UIColor darkGrayColor] CGColor],                                                

      [[UIColor lightGrayColor] CGColor], nil];    

        CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations);   

        CGColorSpaceRelease(colorSpace);  // Release owned Core Foundation object.    

        CGPoint startPoint = CGPointMake(0.0, 0.0);   

          CGPoint endPoint = CGPointMake(CGRectGetMaxX(self.bounds),   

       CGRectGetMaxY(self.bounds));    

         CGContextDrawLinearGradient(ctx, gradient, startPoint, endPoint,  kCGGradientDrawsBeforeStartLocation |     kCGGradientDrawsAfterEndLocation);    

         CGGradientRelease(gradient);  // Release owned Core Foundation object.

    }

    转换旧Project使用ARC时出现的共同问题
    当你运行一个已有的项目时,你可能会遇到几个结果,这些是可能出现的后果及解决方案:
    不能使用retain, release, 或autorelease。这是一个特征,而且以下代码也是不允许的这样的代码也是不允许的:

    while ([x retainCount]) { [x release]; }


    不能使用dealloc。
    一般情况下,对于单例模式或者需要替换一个对象的时候,你会在init函数里面调用dealloc函数。对于单例模式,你可以使用共享模式来替代。因为后 者在init里面不需要调用dealloc,在你从新对self赋值的时候,原内存就被释放,在init方法中,你并不必须调用dealloc,因为你重 构self时,这个对象将会被释放。
    不能使用NSAutoreleasePool 对象。使用新的@autoreleasepool{} 来代替。 它会强制使用一个块在你的autorelease pool,它的速度比NSAutoreleasePool快6倍。甚至@autoreleasepool 还可以在手动内存管理模式下工作。所以无脑使用速度更快的@autoreleasepool来替换掉之前的那些“性能杀手”。

              迁移控制可以使用NSAutoreleasePool但它不能处理复杂的需要考虑的转换,或者用于当变量在 @autoreleasepool的body里被定义的转换之后
    ARC要求在init方法中把[super init]赋值给self。下面的例子是错误的init方法

    [super init];


    应该修改成:

    self = [super init];


    修改后应对,self做nil值检查:

    self = [super init];
       if (self) {
       ...


    你不能自定义实现retain或release方法。实现自定义retain或release方法会破坏weak指针。有下面几个常见的原因来说明为什么不要自定义implementations:

        性能。


        请不要再自定实现这些方法;NSObject中实现retain 和 release 要更快。如果你使用有问题,你应该去解决bug。



        实现weak指针系统。


        使用__weak来代替。 



        实现单例class.


        使用共享模式代替。或者使用类来代替实例函数,来避免对所有的对象分配内存。 


    如果你觉得你必须实现自定义retain或release 方法,那么你必须在你的class中实现下面这个方法:

    -(BOOL)supportsWeakPointers { return NO; }


    这个方法阻止为你的类生成weak指针。但是强烈建议你使用其他的方式来避免实现这些函数。
    你不能在C语言的结构体中使用strong ids。
    举个例子,下面的代码,编译时会报错:

    [pre]struct X { id x; float y; };[/pre]


    这 是因为,x默认是strongly retained的,当你通过一组完成free操作的代码,传递一个指针进这些结构体,每个id都必须在struct被释放前被释放。但是编译器不能可靠 的完成这些,所以结构体中的strong ids在ARC模式中被完全禁止了,必须先释放这些x指向的内存,但是由于是ARC模式,编译器不能安全的去做这些事,所以这些内存泄漏了,所以在C语言 的结构中,ARC禁止使用强指针,下面是可能的解决方案:
    使用Objective-C的对象来代替。
    这是最最最好的方法。
    如果使用Objective-C对象不是最优化的选择, (比如你想要一个大量数组的结构体) ,这时用void* 代替。
    这需要使用显示的转换,下面会讨论。
    使用对象的引用__unsafe_unretained。
    下面的方法可以用于这种比较常见模式:

    struct x { NSString *S;  int X; } StaticArray[] = {  @"foo", 42,  @"bar, 97,...};

    你可以这样定义结构:

    struct x { __unsafe_unretained NSString *S; int X; }

    这样的写法可能会有问题而且不安全,如果在指针里面的实例被释放了。但是这样做和常量字符一样是共识的很有用的东西。你不能直接进行id和void *的转换(包括核心功能中的类型)。这个问题的细节在 “Managing Toll-Free Bridging”里面讨论。
    你不能直接进行id和void *的转换(包括核心功能中的类型)。这个问题的细节在 “Managing Toll-Free Bridging”里面讨论。


    常见Q&A
    我怎么理解ARC? 在哪调用retains/releases?
    你可以不要再去想什么在哪调用retain/release,你可以花更多的精力来思考你的程序逻辑,对象“strong and weak” 引用, 对象的所属关系,循环引用等问题。

    我还需要给对象写dealloc方法吗?
    可能吧。

    因为ARC不会自动malloc/free,不会管理Core Foundation objects的生存周期,文件描述符等等。你还是需要写dealloc方法去释放资源。
    你不需要也不能去release实体变量,但是你需要在系统的类和没有使用ARC的代码中,调用[self setDelegate:nil]。
    在ARC下,dealloc 方法不是必须的,也不能调用[super dealloc];super在运行时执行。
    循环引用在ARC中还有效吗?
    是的。
    ARC自动管理retain/release,,也继承了循环调用。 幸运的是, ARC模式下的代码很少有内存泄漏,因为在声明的时候就已经决定了是否需要retain。

    ARC模式下块如何工作?
    在ARC模式下,你只能再栈上传递块,例如返回语句。你不需要再使用 Block Copy。但你还是必须在为arrayWithObjects: 传入栈的时候使用[^{} copy]和其他的retain功能的函数。
    有一件事情需要提醒,在ARC模式下,__block NSString *S被保留了,它不是一个野指针。使用_block __unsafe_unretained NSString *S 或者 (更好的方式) __block __weak NSString *S.



    我能不能在雪豹Xcode上开发ARC模式的Mac OS程序?
    不行。雪豹版本的Xcode 4.2不支持ARC。雪豹版本没有10.7的SDK,所以在为MAC OS X开发应用的时候不能使用ARC,但是这个版本支持为iOS开发的时候使用ARC。狮子(Lion)版本的是可以的,这意味着你需要在Lion系统中为雪 豹构造一个ARC应用
    我能在ARC模式的工程中创建C语言的数组么?
    当然可以, 如下例所示:

    // Note calloc() to get zero-filled memory.__strong SomeClass **dynamicArray = (__strong SomeClass **)calloc(sizeof(SomeClass *), entries);

    for (int i = 0; i < entries; i++) {   

        dynamicArray[i] = [[SomeClass alloc] init];

    } // 当你完成时,将所有入口赋值为nil使得ARC释放对象

    for (int i = 0; i < entries; i++) {  

       dynamicArray[i] = nil;

    }free(dynamicArray);

    有几点需要注意的是:

        你需要写 __strong SomeClass ** 在某些情况下, 因为默认是__autoreleasing SomeClass **。


        申请的内存空间必须用0填满。



        在释放这个数组前,你必须设置每一个元素为nil(调用memset,并传入0是没有用的)。


        你必须避免使用memcpy 和 realloc。


    使用ARC不会不很慢?
    这 要看你怎么去理解快慢了。但是通常来说“no”,不慢! 编译器有效的排除了很多多余的retain/release的调用,并一直在加快在常规Objective - C代码运行投入很大的努力。尤其是比常规的“返回一个etain/autoreleased 对象”的模式要快得多,而且当调用方法是ARC代码,调用的对象实际上并没有投入autorelease池。
    要注意的一个问题是,优化器不是工作在常规的debug设置里面,所以使用-O0 比-Os出现更多的retain/release。
    ARC可以在ObjC++模式下工作吗?
    可以,你甚至可以在类和容器中使用strong/weak id。ARC在编译时,会在复制构造函数和析构函数中加入retain/release方面的逻辑处理,来确保正常工作。有一点需要避免的就是,你不能为某些指针使用__strong,例如:

    std::vector<__strong NSString*> V;


    那些类不支持zeroing-weak的weak引用?
    下面的类的实例不能使用zeroing-weak的weak引用
    NSATSTypesetter, NSColorSpace, NSFont, NSFontManager, NSFontPanel, NSImage, NSMenuView,NSParagraphStyle,NSSimpleHorizontalTypesetter,NSTableCellView,NSTextView,NSViewController,NSWindow, andNSWindowController. 还有,OS X上的AV Foundation框架中所有类都不支持zeroing-weak的weak引用
    如果属性变量是这些类的实例的时候,使用assign来替代weak;作为变量,使用__unsafe_unretained来替代__weak。
    此外,不用对NSHashTable,NSMapTable, 和NSPointerArray的实例做weak应用。
    在写类似NSCell这样使用NSCopyOjbect的子类的时候,有什么需要特别关注的地方么?
    没什么特殊的。 ARC来关心你以前增加额外的retains。通过ARC,所有复制方法应该只是复制的实例变量。
    我可以为单独文件指定是否使用ARC么?
    可以.
    当 你迁移一个久工程到ARC模式下, -fobjc-arc 编译开关被默认的设置在所有的Objective-C 源代码上。 你可以使用-fno-objc-arc 来为特殊的class停用ARC 。在Xcode的 target的“Build Phases”标签, 打开Compile Sources group,展开源代码列表, 双击你想要修改的源代码的名字,再弹出框里输入-fno-objc-arc,然后点Done按钮。

    (Garbage Collection)是否被Mac废弃了?
    GC 在Mac OS X v10.7依旧可用.。但是强烈建议你在新工程中使用ARC。对旧的工程(使用手动内存管理或GC),建议你试着去改为ARC模式,然而,这是非零量的工作,你应该权衡与其他优先事项比较之后再去做。

     

     

    虽然使用ARC的好处多多,但在选择之前也需要考虑清楚,目前ARC只支持iOS5.0以上系统,在4.0上还不能支持weak reference,而对于解决strong reference cycle问题来说,弱引用是必须的。另外一些第三方库还并不能完美支持ARC,当然这也可以通过为特定文件指定-fno-obj-arc的方法来解决。
        ARC的使用很简单,去掉所有的retain/release/dealloc/autorelease方法,把原来property声明里的retain改为strong,assign改为weak,再把NSAutoReleasePool替换为@autoreleasepool即可满足绝大多数情况。
        另外还有一些需要注意的,包括属性名不能以new打头,不能显式调用dealloc但是可以实现自定义的dealloc方法,但是不要在方法中销毁内部变量,只需要翻译资源,同时也不需要调用[super dealloc],ARC为帮助完成这些操作。
        还有一些__strong、__weak、__unsafe_unretained、__autorelease标识符在绝大多数情况下都不会使用到,默认的__strong标识符即可以,而且也不需要显式的指明。
        需要注意的是,临时变量使用__weak标签的时候一定要小心,如果方法返回的是autorelease类型,将其赋值给__weak变量的时候,因为此时已经没有了强引用,该变量已不再存在,所以__weak变量获取到的值会是nil。
        类似的,如果方法返回的是__autorelease类型的对象指针,将其赋值给__strong变量,虽然运行结果是正确的,但是其内部行为并不如所期望的那样,会生成一个临时变量,具体说明可以参见apple官方文档。
        关于在C结构体中使用对象指针的问题,官方建议使用class代替,当然也可以将该文件指定为不使用ARC。
        最后,Toll Free Bridging只有在使用Core Foundtion库的时候才会遇到,一般情况下不用太在意。
     

     

     

     

     

     

     

     
  • 相关阅读:
    hinge loss
    KL散度
    pygame 学习
    pytorch 反向传播
    在线画数学函数图
    recover deleted files
    98个关键点的人脸
    Pytorch详解BCELoss和BCEWithLogitsLoss
    one hot vector
    Effective C++
  • 原文地址:https://www.cnblogs.com/jiangshiyong/p/2540620.html
Copyright © 2011-2022 走看看