本文转载至 http://blog.csdn.net/allison162004/article/details/38758265
自动引用计数(ARC)是编译器的一个特色,提供了Objective-C对象的自动内存管理机制。比起不得不考虑retain和release操作,ARC让你更加专注于应用中那些有趣的代码,如对象图,对象关系。
摘要(Summary)
通过在编译期添加代码的方式,ARC保证所有对象按需存在,按需释放。从概念上来讲,它与手动引用计数(参见 )有着相同的内存管理约定,二者都会为你添加合适的内存管理方法调用。 为了编译器能生成正确的代码,ARC限定了你可以使用的一些方法,以及toll-free桥接的使用方式(参见 ).与此同时ARC还为对象引用(object references )和声明式属性(declared properties)引进了新的生命周期限定符(lifetime qualifiers )。 ARC适用于OS X v10.6和v10.7(64位)下的Xcode4.2,以及IOS 4和IOS5.OS X v10.6和IOS4不支持弱引用。Xcode提供了自动化的工具,完成ARC转换过程中需要手工操作的部分(例如删除retain和release方法调用),并且帮助你在 迁移过程中不能自动完成的操作(选择Edit->Refactor->Convert to Objective-C ARC)。迁移工具将工程中的所有文件使用ARC进行转换。如果你觉得在某些文件中使用手动引用计数会更方便,那么你也可以选择在单独文件中使用ARC。
参见:ARC概述(ARC Overview)
ARC会评估对象所需的生命期,并会在编译期为你自动插入合适的内存管理调用方法,取代之前你不得不考虑何时需要使用 , 以及 的操作方式。编译器也会为你生成合适的 方法。总的来说,如果你仅使用ARC,传统的Cocoa命名规范只会在你需要与使用手动引用计数的代码交互时才是重要的。一个完整正确的Person类的实现看起来可能是这样的:
- @interface Person : NSObject
- @property NSString *firstName;
- @property NSString *lastName;
- @property NSNumber *yearOfBirth;
- @property Person *spouse;
- @end
- @implementation Person
- @end
- - (void)contrived
- {
- Person *aPerson = [[Person alloc] init];
- [aPerson setFirstName:@"William"];
- [aPerson setLastName:@"Dudney"];
- [aPerson setYearOfBirth:[[NSNumber alloc] initWithInteger:2011]];
- NSLog(@"aPerson: %@", aPerson);
- }
- - (void)takeLastNameFrom:(Person *)person {
- NSString *oldLastname = [self lastName];
- [self setLastName:[person lastName]];
- NSLog(@"Lastname changed from %@ to %@", oldLastname, [self lastName]);
- }
- // Won't work:
- @property NSString *newTitle;
- // Works:
- @property (getter=theNewTitle) NSString *newTitle;
- // 以下声明等价于 @property(retain) MyClass *myObject;
- @property(strong) MyClass *myObject;
- // 以下声明等价于"@property(assign) MyClass *myObject;"
- // 不同之处在于如果MyClass的实例变量释放时,其属性值会设置为nil,而不会保存为一个野指针
- @property(weak) MyClass *myObject;
- <span style="font-family: 宋体;">__strong </span>
- <span style="font-family: 宋体;">__weak </span>
- __unsafe_unretained
- __autoreleasing
- ClassName * qualifier variableName;
- MyClass * __weak myWeakReference;
- MyClass * __unsafe_unretained myUnsafeReference;
- NSString * __weak string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]];
- NSLog(@"string: %@", string);
- NSError *error;
- BOOL OK = [myObject performOperationWithError:&error];
- if (!OK) {
- NSError * __strong e;
- -(BOOL)performOperationWithError:(NSError * __autoreleasing *)error;
- NSError * __strong error;
- NSError * __autoreleasing tmp = error;
- BOOL OK = [myObject performOperationWithError:&tmp];
- error = tmp;
- if (!OK) {
- MyViewController *myController = [[MyViewController alloc] init…];
- // ...
- myController.completionHandler = ^(NSInteger result) {
- [myController dismissViewControllerAnimated:YES completion:nil];
- };
- [self presentViewController:myController animated:YES completion:^{
- [myController release];
- }];
- MyViewController * __block myController = [[MyViewController alloc] init…];
- // ...
- myController.completionHandler = ^(NSInteger result) {
- [myController dismissViewControllerAnimated:YES completion:nil];
- myController = nil;
- };
- MyViewController *myController = [[MyViewController alloc] init…];
- // ...
- MyViewController * __weak weakMyViewController = myController;
- myController.completionHandler = ^(NSInteger result) {
- [weakMyViewController dismissViewControllerAnimated:YES completion:nil];
- };
- MyViewController *myController = [[MyViewController alloc] init…];
- // ...
- MyViewController * __weak weakMyController = myController;
- myController.completionHandler = ^(NSInteger result) {
- MyViewController *strongMyController = weakMyController;
- if (strongMyController) {
- // ...
- [strongMyController dismissViewControllerAnimated:YES completion:nil];
- // ...
- }
- else {
- // Probably nothing...
- }
- };
- @autoreleasepool {
- // Code, such as a loop that creates a large number of temporary objects.
- }
- - (void)myMethod {
- NSString *name;
- NSLog(@"name: %@", name);
- }
- - (void)logFirstNameOfPerson:(ABRecordRef)person {
- NSString *name = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
- NSLog(@"Person's first name: %@", name);
- [name release];
- }
- - (void)logFirstNameOfPerson:(ABRecordRef)person {
- NSString *name = (NSString *)CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
- NSLog(@"Person's first name: %@", name);
- }
- NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]];
- [colors addObject:(id)[[UIColor lightGrayColor] CGColor]];
- NSArray *colors = <#An array of colors#>;
- 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};
- NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]];
- [colors addObject:(id)[[UIColor lightGrayColor] CGColor]];
- 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.
- }
- [super init];
- self = [super init];
- self = [super init];
- if (self) {
- @interface MyClass : Superclass {
- id thing; // Weak reference.
- }
- // ...
- @end
- @implementation MyClass
- - (id)thing {
- return thing;
- }
- - (void)setThing:(id)newThing {
- thing = newThing;
- }
- // ...
- @end
- @interface MyClass : Superclass {
- id __weak thing;
- }
- // ...
- @end
- @implementation MyClass
- - (id)thing {
- return thing;
- }
- - (void)setThing:(id)newThing {
- thing = newThing;
- }
- // ...
- @end
- 或
- @interface MyClass : Superclass
- @property (weak) id thing;
- // ...
- @end
- @implementation MyClass
- @synthesize thing;
- // ...
- @end
struct X { id x; float y; };
因为x默认肯定是被保留的,编译器无法安全的合成所有保证代码正常运转所需的所有代码。例如,如果你通过一些最终会被释放的代码来传入一个指针到这些结构 体后,每个id在结构体回收之前会被被迫释放掉。编译器不能可靠的做到这点,所以在结构体中的强类型的ids在ARC模式下是完全无效的。以下有几个可能 的解决办法:
(1)使用Objective-C对象代替结构体 这是最好的实践方法。 (2)如果使用Objective-C对象是次优方案,(可能你想要这些结构体组成的一个数组)那么考虑void *进行替代。 这需要使用显示的类型转换,在下面会提到。 (3)将对象引用标记为__unsafe_unretained 该方法对于一些不常见的模式可能会有效,如下:
- struct x { NSString *S; int X;}
- StaticArray[]={
- @"foo", 42,
- @"bar",97,
- };
- // 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];
- }
- // When you're done, set each entry to nil to tell ARC to release the object.
- for (int i = 0; i < entries; i++) {
- dynamicArray[i] = nil;
- }
- free(dynamicArray);
有些其它需要注意的地方:
某些情况下你需要使用__strong SomeClass **,因为默认是__autoreleasing SomeClass **. 分配的内存必须是零填充的 你必须在释放数组(memset或bzero无法工作)之前将每个元素设置为nil. 避免使用memcpy或realloc ARC运行速度会慢吗? 这取决于你的测量方式,但基本”很快“。编译器高效的消除许多外部的 retian和 release调用,而且总的来说会更加关注于提升Objective-C运行时的速度。尤其是,当调用者是ARC代码时,常用的"返回一个 retain/autoreleased对象"模式会更快速而且实际上并没有将对象放入到自动释放池中。 我可以在特定文件下退出ARC吗?可以。 在你迁移工程来使用ARC时,-fobjc-arc编译器标记默认会设置到每个Objective-C的源文件。你可以使用 -fno-objc-arc编译器标记来在特定的类中禁用ARC。在Xcode中,在target的 Build Phases中,打开 Compile Sources 组显示源文件列表。双击你想要设置标记的文件,在pop-up面板中输入-fno-objc-arc指定,之后点击完成。