原文是由前人总结翻译的,本人觉得不错,就直接转过来了。
自动引用计数(ARC),是一项为Objective - C程序在编译时提供自动内存管理的功能。ARC可以让你把注意力集中在你感兴趣的代码,对象图,和你的应用程序中的对象之间的关系,让你不必再花费精力在retain和release操作上。正如下图所示,ARC可以减少开发中的内存管理步骤,简化开发。Contents:
Summary
ARC Overview
Managing Toll-Free Bridging
Common Issues While Converting a Project
Frequently Asked Questions
概要
ARC工作方式是在代码编译的时候,自动加入内存控制代码,来控制对象的生命周期,确保对象使用的内存空间正确的分配和释放。从概念上来说,ARC遵循Advanced Memory Management Programming Guide的手动内存使用守则,通过加入retain,release,autorelease 方法,确保实现与你手动管理内存一样的效果。
为了代码能正常编译,ARC对toll-free bridging(详见“Toll-Free Bridged Types”)使用的方式、方法进行了限制,同时ARC还为对象和声明的属性引入了新的生命周期。
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。
Xcode中加入了一个新的工具,用于自动处理ARC里机械式的操作,如移出项目代码中的retain和release方法 调用),而且它还可以帮你修订那些不能自动移植的代码。这个代码移植工具,支持转化项目中的所有代码为ARC模式,如果觉得不方便,你也可以选择手动方式来处理这些文件。
参考资料:
Memory Management Programming Guide for Core Foundation
ARC概述
ARC可以代替你去记住何时应该 retain ,何时应该 release ,何时要 autorelease ;ARC回为你评估你的项目所需的生命周期,并且自动地在编译时为你调用适当的方法。编译器还可以帮你生成 dealloc 方法。一般来说,如果你只使用ARC,当你需要使用手动引用计数的代码互操作的时候,常规Cocoa命名规约是重要的。
一个完整、正确的,用来描述“Person”特性的类的实现(implementation),是这样的:
- @interface Person : NSObject@property (nonatomic, strong) NSString *firstName;@property (nonatomic, strong) NSString *lastName;@property (nonatomic, strong) NSNumber *yearOfBirth;@property (nonatomic, strong) Person *spouse;@end @implementation Person@synthesize firstName, lastName, yearOfBirth, spouse;@end
( strong 属性的描述参见 “ARC Introduces New Lifetime Qualifiers” .)
使用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。
- 不可以再显示调用dealloc、或实现调用retain、release、retainCount、autorelease这些方法。
当你需要管理一些非实例变量的资源时,你可以实现一个dealloc方法。你不需要也不能去释放实例变量,但您可以调用[systemClassInstance setDelegate:nil]或不使用ARC编译的内存管理代码。
在ARC下去自定义dealloc方法不需要调用 [super dealloc],(实际上如果你调用了 [super dealloc],编译器会报错)。super的调用是由编译器自动强制执行的。
CFRetain, CFRelease, 还有其他Core Foundation-style objects函数 (详见“Managing Toll-Free Bridging”)还是可以执行的。
- 不能使用NSAllocateObject或NSDeallocateObject。
使用
不能在C语言的结构体中使用对象指针。
建议使用Objective-C的class来管理数据格式,来代替C语言的struct。
不能隐式转换 id和void *。
你必须告诉编译器转换的类型。当你需要在obj-C的对象和Core Foundation 类型之间转换时,你可以通过函数的参数来做。详见“Managing Toll-Free Bridging”。
不能使用 NSAutoreleasePool对象。
ARC提供了一个@autoreleasepool块来代替,这个块相比NSAutoreleasePool来说,具有更高的有效性。
不能使用memory Zone。
因为现在Objective-C运行时已经忽略NSZone了,所以没必要再使用NSZone了。
为了可以和手动内存管理(manual retain-release)的代码兼容,ARC提出了一些变量方法的命名规约。
- 你不能用“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;"是相似的,// 但是,当 MyClass 被释放的时候,值被设为nil,而不是一个野指针 @property(weak) MyClass *myObject;
变量修饰符
你可以用下面的生命周期修饰符来声明变量,就像你使用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; |
那么,编译器会重写代码,变成:
- NSError __strong *error = nil;NSError __autoreleasing *tmp = error;BOOL OK = [myObject performOperationWithError:&tmp];error = tmp;if (!OK) { // Report the error. // ...
当本地变量声明(__strong *error)和函数的参数((NSError * __autoreleasing *)error)不匹配的时候,编译器会创建一个临时变量。当你获得一个__strong变量的地址时,你可以初始化一个id __strong *的指针来声明 ,这样你就可以获得指针的原型,或者你可以声明一个变量为__autoreleasing。
使用生命周期修饰符来避免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变量。下面的例子下面的例子说明了一个简单的实现:
- MyViewController *myController = [[MyViewController alloc] init…];// ...__weak MyViewController *weakMyViewController = myController;myController.completionHandler = ^(NSInteger result) { [weakMyViewController dismissViewControllerAnimated:YES completion:nil];};
对于一般情况,你可以这样来做:
- 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本身 (例如 CFArrayRef 和 CFMutableDictionaryRef )或是由Core Foundation扩展出的framework,例如Core Graphics (例如 CGColorSpaceRef 和 CGGradientRef ).
编译器不会自动管理Core Foundation对象的生命周期;你必须使用 CFRetain 和 CFRelease (或相应的特殊类型的变量) 来符合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:[[UIColor darkGrayColor] 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.
使用共享模式代替。或者使用类来代替实例函数,来避免对所有的对象分配内存。
-(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。
这要看你怎么去理解快慢了。但是通常来说“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按钮。
![08133945_NVNR.png](https://i-blog.csdnimg.cn/blog_migrate/e75979a9416edb0b87430490302576bb.png)
GC 在Mac OS X v10.7依旧可用.。但是强烈建议你在新工程中使用ARC。对旧的工程(使用手动内存管理或GC),建议你试着去改为ARC模式,然而,这是非零量的工作,你应该权衡与其他优先事项比较之后再去做。