自动引用计数(ARC),是一项为Objective - C程序在编译时提供自动内存管理的功能。ARC可以让你把注意力集中在你感兴趣的代码,对象图,和你的应用程序中的对象之间的关系,让你不必再花费精力在retain和release操作上。正如下图所示,ARC可以减少开发中的内存管理步骤,简化开发。
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模式,如果觉得不方便,你也可以选择手动方式来处理这些文件。
参考资料:
Advanced Memory Management Programming Guide
Memory Management Programming Guide for Core Foundation
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引入了一些特有的新规则。新规则的用于提供一个完整可靠的内存管理模式;这些规则有些是用于更好的用户体验,另外一些则是用于简化你的编码,或让你不必再为内存管理操心。如果你违反了这些规则,在你编译的时候就会报错了,而不是当你编译成功,开始运行时出现一些bug。
不可以再显示调用dealloc、或实现调用retain、release、retainCount、autorelease这些方法。
很明显也不能使用@selector(retain)
, @selector(release)
,等等。
当你需要管理一些非实例变量的资源时,你可以实现一个dealloc方法。你不需要也不能去释放实例变量,但您可以调用[systemClassInstance setDelegate:nil]
或不使用ARC编译的内存管理代码。
在ARC下去自定义dealloc方法不需要调用 [super dealloc]
,(实际上如果你调用了 [super dealloc]
,编译器会报错)。super的调用是由编译器自动强制执行的。
CFRetain, CFRelease, 还有其他Core Foundation-style objects函数 (详见“Managing Toll-Free Bridging”)还是可以执行的。
不能使用
NSAllocateObject
或NSDeallocateObject
。
使用alloc
来创建对象,由ARC来管理对象运行时的释放。
不能在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引入了一些新的生命周期修饰符和zeroing weak引用.。一个weak引用不会改变它所指向对象的生命周期。 一个zeroing weak引用会在它指向的对象被释放以后,自动赋为nil。
在你的程序中,你应该灵活运用修饰符来管理你的对象图。特别是,ARC不会去保护strong引用的retain周期(详见“Practical Memory Management”),所以谨慎使用weak可以确保你不会创建循环引用。
在下面的几个例子中,我们介绍一下新的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引用,子类指向父类为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,你不能再使用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
代码都改成新的模式。
在被ARC处理过的iOS和OS X中,声明的outlets将会趋于统一。
一般来说outlets变量被修饰为weak,但是如果outlets变量的所有者是nib文件中的top-level对象(或者是storyboard scene)时,应被修饰为strong。
详细参考Resource Programming Guide中的“Nib Files”。
使用ARC模式,strong,weak,autoreleasing栈变量都被隐式的初始化为nil,例如:
- (void)myMethod { |
NSString *name; |
NSLog(@"name: %@", name); |
} |
运行是程序不会崩溃,NSLog会打印出“null”。
你可以使用 -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.
在许多的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 CFRef |
CFStringRef d = (__bridge_retained CFStringRef)my_id; // returned CFRef is +1 |
编译器理解遵从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. |
} |
当你运行一个已有的项目时,你可能会遇到几个结果,这些是可能出现的后果及解决方案:
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
但它不能处理复杂的需要考虑的转换,或者用于当变量在
@autoreleasepoo
l的body里被定义的转换之后
下面的例子是错误的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指针。但是强烈建议你使用其他的方式来避免实现这些函数。
id
s。
举个例子,下面的代码,编译时会报错:
struct X { id x; float y; }; |
这是因为,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; } |
这个问题的细节在 “Managing Toll-Free Bridging”里面讨论。
我怎么理解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按钮。
GC (Garbage Collection)是否被Mac废弃了?
GC 在Mac OS X v10.7依旧可用.。但是强烈建议你在新工程中使用ARC。对旧的工程(使用手动内存管理或GC),建议你试着去改为ARC模式,然而,这是非零量的工作,你应该权衡与其他优先事项比较之后再去做。