ARC是iOS 5推出的新功能,全称叫 ARC(Automatic Reference Counting)。简单地说,就是代码中自动加入了retain/release,原先需要手动添加的用来处理内存管理的引用计数的代码可以自动地由编译器完成了。
该机能在 iOS 5/ Mac OS X 10.7 开始导入,利用 Xcode4.2 可以使用该机能。简单地理解ARC,就是通过指定的语法,让编译器(LLVM 3.0)在编译代码时,自动生成实例的引用计数管理部分代码。有一点,ARC并不是GC,它只是一种代码静态分析(Static Analyzer)工具。
//ARC使用前
@interface NonARCObject : NSObject {
NSString *name;
}
-(id)initWithName:(NSString *)name;
@end
@implementation NonARCObject
-(id)initWithName:(NSString *)newName {
self = [super init];
if (self) {
name = [newName retain];
}
return self;
}
-(void)dealloc {
[name release];
[Super dealloc];
}
@end
//ARC使用后
@interface ARCObject : NSObject {
NSString *name;
}
-(id)initWithName:(NSString *)name;
@end
@implementation ARCObject
-(id)initWithName:(NSString *)newName {
self = [super init];
if (self) {
name = newName;
}
return self;
}
@end
曾经都是这么使用,retain使引用计数+1后使用autorelease自动释放
return [[object retain] autorelease];
而使用ARC后,我们可以不需要这样做了,甚至连最基础的release都不需要了。
ARC的好处
如果有像我一样从Java转oc的朋友一定觉得这个太棒了,
1、内存的管理交给编译器处理,不需要我们在担心内存管理上的不当造成泄漏
2、代码变少了,-(void)dealloc{ [x release]; [y release]; }
3、降低大家的错误释放造成低效代码
ARC的缺点
1、有朋友说游戏开发的一些大牛还是习惯手动释放,这样效率会更高!个人比较向往
2、重构一些旧项目,XCode4.2 中缺省ARC就是 ON 的状态,所以编译旧代码的时候往往有"Automatic Reference Counting Issue"的错误信息。
这个时候,可以将项目编译设置中的“Objectice-C Auto Reference Counteting”设为NO
如果只想对某个.m文件不适应ARC,可以只针对该类文件加上 -fno-objc-arc 编译FLAGS
ARC基本规则
retain, release, autorelease, dealloc由编译器自动插入,不能在代码中调用
dealloc虽然可以被重载,但是不能调用[super dealloc]
由于ARC并不是GC,并需要一些规则让编译器支持代码插入,所以必须清楚清楚了这些规则后,才能写出健壮的代码。
OC中的对象
强参照(Strong reference)和弱参照(Weak reference)之分,当需要保持其他对象的时候,需要retain以确保对象引用计数加1。对象的持有者(owner)只要存在,那么该对象的强参照就一直存在。
//1
NSString *test1 = [[NSString alloc] initWithString:@"test1"];
//2
NSString *test2 = test1;
//3
test1 = [[NSString alloc] initWithString:@"test1Change"];
//4
NSString *test3 = test1;
//5
test2 = test3;
1、test1作为'test1'对象的最初持有者,是NSString类型对象的强参照
2、将test1带入test2,这里test2也是强参照
3、test1改变内容,生成test1Change字符串,test1变成了该字符串的拥有者,而‘test1’字符串只有test2拥有,他们都在内存中存在
4、test1赋值给test3,这里也是强参照
5、test3赋值给test2,这里的‘Test1’字符串没有拥有者,该对象被释放
弱参照
//1
NSString *test1 = [[NSString alloc] initWithString:@"test1"];
_weak NSString *test2 = test1;
这里当test1被释放时,test2为nil。
NSString __weak *string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]];
NSLog(@"string: %@", string); //此时 string为空