Automatic Reference Counting (ARC)是編譯器自動管理Objective-C對象的一個功能,相對於不得不考慮retain和release操做來講,ARC讓咱們有更多的精力集中在咱們應用內有趣的代碼、object graphs和對象之間的關係上。安全
ARC是用過來在編譯的時候添加適當的代碼來保證對象在有用的時候有效,沒有了就再也不有效了。從概念上講,ARC經過調用合適的內存管理方法遵循着和 manual reference counting(MRC)一樣的內存管理規則。app
爲了讓編譯器產生正確的代碼,ARC嚴格規定了你能夠調用的方法和怎樣使用toll-free bridging。ARC引入了新的用於對象引用和屬性聲明的生命週期標識符。函數
ARC支持Xcode 4.2 for OS X v10.6 and v10.7 (64-bit applications) and for iOS 4 and iOS 5。弱引用不支持OS X v10.6 and iOS 4。工具
Xcode提供了一個工具用來把非ARC代碼自動轉換到ARC代碼(例如移除retain和release的調用),解決的不能自動遷移的問題。這個工具會把工程中的全部文件都轉換成ARC,在使用非ARC方便的狀況下,你也能夠選擇某些文件使用ARC。oop
不用再記住何時該使用retain、release和autorelease了,ARC知道你的對象的使用週期而後在編譯的時候加入了合適的內存管理代碼。編譯器也會爲你生成合適的dealloc方法。若是你剛剛使用ARC,那麼傳統的Cocoa的命名規範在你管理MRC的代碼的時候是很是重要的。性能
一個完整的正確的Person類的實現是這樣的:spa
@interface Person : NSObject @property NSString *firstName; @property NSString *lastName; @property NSNumber *yearOfBirth; @property Person *spouse; @end @implementation Person @end
對象的屬性默認是strong的。指針
使用ARC,你可能實現這樣一個方法contrived :code
- (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都不會形成內存泄露。orm
你也能夠安全的實現一個Person的方法takeLastNameFrom:
- (void)takeLastNameFrom:(Person *)person { NSString *oldLastname = [self lastName]; [self setLastName:[person lastName]]; NSLog(@"Lastname changed from %@ to %@", oldLastname, [self lastName]); }
ARC可以確保 oldLastName
在NSLog以前不被釋放。
ARC提出了一些新的別的編譯器沒有的新規則。這些規定是爲了可以提供一個完整的可靠的內存管理模型。在一些狀況可以很簡單的提高性能,在一些狀況下可以簡化代碼或者讓你不用處理內存管理。若是你違背這些規則,在編譯的時候就會出錯,而不是在運行的時候產生錯誤。
@selector(retain)
,
@selector(release)等等
NSAllocateObject 和
NSDeallocateObject
// Won't work: @property NSString *newTitle; // Works: @property (getter=theNewTitle) NSString *newTitle;
// The following declaration is a synonym for: @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;在ARC下,strong是默認的對象類型。
__strong __weak __unsafe_unretained __autoreleasing
ClassName * qualifier variableName;例如:
MyClass * __weak myWeakReference; MyClass * __unsafe_unretained myUnsafeReference;其餘變種寫法在技術上是不正確的,當時是被編譯器容許,想要了解更過能夠看這裏: http://cdecl.org/
NSString * __weak string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]]; NSLog(@"string: %@", string);雖然string是在初始化賦值以後使用的,可是在賦值的時候沒有強引用指向string,所以它馬上就會被釋放。NSLog語句會輸出一個null值(在此例子中編譯器會給出警告)。
NSError *error; BOOL OK = [myObject performOperationWithError:&error]; if (!OK) { // Report the error. // ...然而這個聲明是錯誤的並且是隱式的。
NSError * __strong e;其實這個方法的聲明以下:
-(BOOL)performOperationWithError:(NSError * __autoreleasing *)error;
NSError * __strong error; NSError * __autoreleasing tmp = error; BOOL OK = [myObject performOperationWithError:&tmp]; error = tmp; if (!OK) { // Report the error. // ...
MyViewController *myController = [[MyViewController alloc] init…]; // ... myController.completionHandler = ^(NSInteger result) { [myController dismissViewControllerAnimated:YES completion:nil]; }; [self presentViewController:myController animated:YES completion:^{ [myController release]; }];正像是描述的同樣,你可使用__block標識符,在completion handler內設置myController爲nil:
MyViewController * __block myController = [[MyViewController alloc] init…]; // ... myController.completionHandler = ^(NSInteger result) { [myController dismissViewControllerAnimated:YES completion:nil]; myController = nil; };另外,你可使用一個臨時的__weak變量。下面的例子聲明瞭一個簡單是實現:
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... } };在一些狀況下若是__weak是不兼容的你可能使用__unsafe__unretained。然而對於循環引用這個可能變得不切實際,由於是很是可貴或者不可能驗證__unsafe__unretained指針是有效的和指向了一樣有問題的對象。
@autoreleasepool { // Code, such as a loop that creates a large number of temporary objects. }這個簡單的結構能夠容許編譯器來推斷引用計數狀態。在入口處,一個autorelease pool被放進棧。在退出的地方(break,return,goto,fall-through等等)autorelease pool被彈出棧。爲了兼容已經存在的代碼,若是因爲異常退出,autorelease pool是不會被彈出棧的。
- (void)myMethod { NSString *name; NSLog(@"name: %@", name); }NSLog語句將會輸出null而不是crashing。