http://developer.apple.com/library/mac/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html
Automatic Reference Counting (ARC)是一个编译器的功能,提供了对Objective-C对象的自动内存管理。ARC在编译期间自动在适当的地方添加Objective-C对象的retain和release操作代码。
一. 总结
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 4、iOS 5。weak不支持OS X v10.6和iOS 4。
Xcode提供一个把手动引用计数转换成ARC的工具,choose Edit > Refactor > Convert to Objective-C 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 |
一个contrived方法如下:
- (void)contrived { |
Person *aPerson = [[Person alloc] init]; |
[aPerson setFirstName:@"William"]; |
[aPerson setLastName:@"Dudney"]; |
[aPerson setYearOfBirth:[[NSNumber alloc] initWithInteger:2011]]; |
NSLog(@"aPerson: %@", aPerson); |
} |
三.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
strong和retain相似,只要有一个strong指针指向对象,该对象就不会被销毁;(一个对象,要是没有任何一个strong引用指向该对象,将马上被销毁);
weak,声明为weak的指针,weak指针指向的对象一旦被释放,weak的指针都将被赋值为nil;
unsafe_unretained,用unsafe_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 对象(例如CFArrayRef
、CFMutableDictionaryRef、
、 CGColorSpaceRef
CGGradientRef
)的内存释放,你必须使用CFRetain
and CFRelease管理
Core Foundation-style对象。
Objective-C对象和Core Foundation-style对象的转换,你需要显式告诉编译器转换后的对象的所有权。
a) __bridge,只做类型转换,但是不修改对象(内存)管理权;
b) __bridge_retained或
CFBridgingRetain,将Objective-C的对象转换为Core Foundation的对象,同时将对象(内存)的管理权交给我们,后续需要使用CFRelease或者相关方法来释放对象;
c)
__bridge_transfer
或
CFBridgingRelease
,将Core Foundation的对象转换为Objective-C的对象,同时将对象(内存)的管理权交给ARC。
九. 手动转换项目支持ARC
a) 不能调用retain
, release
, autorelease
.方法;
b) 不能调用dealloc方法;例如:[super dealloc];
c) 用@autorelesepool{}代替NSAutoreleasePool;
d) init初始化方法, [super init]
改成 self = [super
init];
[super init];//错误 |
self = [super init];//正确 |
if (self) { |
... |
使用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
不支持这些类的对象
:
NSATSTypesetter
, NSColorSpace
, NSFont
, NSMenuView
, NSParagraphStyle
, NSSimpleHorizontalTypesetter
, and NSTextView
。
b) ARC不支持管理的内容: malloc
/free分配的对象
, Core Foundation-style 对象, file descriptors。
Core Foundation-style 对象,它是由C的struct定义的各种对象,主要来自于CoreFoundation框架(如CFArray或者CFMutableDictionaryRef类型),或者其它采用CoreFoundation命名规范的框架,如Core Graphics(如,CGColorSpaceRef 和CGGradientRef)。