自動引用計數(ARC)是一種編譯器功能,它提供 Objective-C 對象的自動內存管理。ARC 不是必須考慮 retain 和 release 操做,而是讓你專一於有趣的代碼,對象圖以及應用程序中對象之間的關係。算法
ARC 的工做原理是在編譯時添加代碼,以確保對象在必要時存活,但不會一直存活。從概念上講,它經過爲你添加適當的內存管理調用,遵循與手動引用計數相同的內存管理約定。數組
爲了讓編譯器生成正確的代碼,ARC 限制了你可使用的方法以及如何使用免費橋接(toll-free bridging)。ARC 還爲對象引用和聲明的屬性引入了新的生命週期限定符。安全
ARC 在 Xcode 4.2 編譯的 OS X v10.6 和 v10.7 (64位應用程序) 以及 iOS 4 和 iOS 5 應用程序中提供支持。OS X v10.6 和 iOS 4 不支持弱引用。框架
Xcode 提供了一個工具,能夠自動執行 ARC 轉換的機械部分(例如刪除 retain 和 release 調用),並幫助你修復遷移器沒法自動處理的問題(選擇 Edit > Refactor > Convert to Objective-C ARC)。遷移工具將項目中的全部文件轉換爲使用 ARC。若是對某些文件使用手動引用計數更方便,也能夠選擇在每一個文件的基礎上使用 ARC。ide
ARC 不會記住什麼時候使用 retain,release 和 autorelease,而是評估對象的生命週期要求,並在編譯時自動爲你插入適當的內存管理調用。編譯器還會爲你生成適當的 dealloc 方法。一般,若是你只使用 ARC,則只有在須要與使用手動引用計數的代碼進行互操做時,傳統的 Cocoa 命名約定纔是重要的。函數
Person 類的完整且正確的實現可能以下所示:工具
@interface Person : NSObject
@property NSString *firstName;
@property NSString *lastName;
@property NSNumber *yearOfBirth;
@property Person *spouse;
@end
@implementation Person
@end
複製代碼
(默認狀況下,對象屬性是 strong。)oop
使用 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 強制使用其餘編譯器模式時不存在的一些新規則。規則旨在提供徹底可靠的內存管理模型; 在某些狀況下,他們只是執行最佳實踐,在其餘一些狀況下,他們簡化了代碼,或者是你沒必要處理內存管理的明顯推論。若是違反這些規則,則會當即獲得編譯時錯誤,而不是在運行時可能會出現的細微錯誤。
你沒法顯式調用 dealloc,也沒法實現或調用 retain,release,retainCount 或 autorelease。
禁止擴展到使用 @selector(retain),@selector(release) 等。
若是須要管理除釋放實例變量以外的資源,則能夠實現 dealloc 方法。你沒必要(實際上你不能)釋放實例變量,但你可能須要在系統類和未使用 ARC 編譯的其餘代碼上調用 [systemClassInstance setDelegate:nil]。
ARC 中的自定義 dealloc 方法不須要調用 [super dealloc](它實際上會致使編譯器錯誤)。連接到 super 是由編譯器自動執行的。
你仍然能夠將 CFRetain,CFRelease 和其餘相關功能與 Core Foundation 樣式的對象一塊兒使用。
你不能使用 NSAllocateObject 或 NSDeallocateObject。
你可使用 alloc 建立對象; 運行時負責 deallocating 對象。
你不能在 C 結構中使用對象指針。
你能夠建立一個 Objective-C 類來管理數據,而不是使用結構。
id 和 void * 之間不是簡單的映射。
你必須使用特殊的強制轉換來告訴編譯器有關對象的生命週期。你須要在 Objective-C 對象和做爲函數參數傳遞的 Core Foundation 類型之間進行轉換。
你不能使用 NSAutoreleasePool 對象。
ARC 提供了 @autoreleasepool 塊。它們具備比 NSAutoreleasePool 更有效的優勢。
你不能使用內存區域(memory zones)。
再也不須要使用 NSZone - 不管如何它們都會被現代的 Objective-C 運行時忽略。
爲了容許與 manual retain-release 代碼進行互操做,ARC 對方法命名施加了約束:
// Won't work:
@property NSString *newTitle;
// Works:
@property (getter=theNewTitle) NSString *newTitle;
複製代碼
ARC 爲對象和弱引用引入了幾個新的生命週期限定符。弱引用不會延長它指向的對象的生命週期,而且在沒有對該對象的強引用時自動變爲 nil。
你應該利用這些限定符來管理程序中的對象圖。特別是,ARC不能防範強引用循環(之前稱爲 retain cycles)。明智地使用弱飲用將有助於確保你不會建立循環引用。
關鍵字 weak 和 strong 將做爲新聲明的屬性特性引入,如如下示例所示。
// 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 是對象類型的默認值。
你能夠像使用 const 同樣爲變量使用如下生命週期限定符。
__strong
__weak
__unsafe_unretained
__autoreleasing
複製代碼
你應該正確裝飾變量。在對象變量聲明中使用限定符時,正確的格式爲:
ClassName * qualifier variableName;
複製代碼
例如:
MyClass * __weak myWeakReference;
MyClass * __unsafe_unretained myUnsafeReference;
複製代碼
其餘變體在技術上是不正確的,但編譯器「原諒」了。
在棧上使用 __weak 變量時要當心。請考慮如下示例:
NSString * __weak string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]];
NSLog(@"string: %@", string);
複製代碼
儘管在初始賦值以後使用了字符串,但在賦值時沒有對字符串對象的其餘強引用; 所以,它當即被釋放。log 語句顯示 string 的值爲 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.
// ...
複製代碼
局部變量聲明(__strong)和參數(__autoreleasing)之間的不匹配會致使編譯器建立臨時變量。當你獲取 __strong 變量的地址時,能夠經過聲明參數 id __strong * 來獲取原始指針。或者,你能夠將變量聲明爲 __autoreleasing。
你可使用生命週期限定符來避免強引用循環。例如,一般若是你有一個以父子層次結構排列的對象圖表,而且父對象須要引用他們的孩子,反之亦然,那麼你將使父對象指向子對象之間的引用爲強引用,而且父對象與子對象之間的引用爲弱引用。其餘狀況可能更微妙,特別是當它們涉及 block 對象時。
在手動引用計數模式下,__block id x; 具備不保留 x 的效果。在 ARC 模式下,__block id x; 默認爲保留 x(就像全部其餘值同樣)。要在 ARC 下得到手動引用計數模式行爲,可使用 __unsafe_unretained __block id x;。然而,正如名稱 __unsafe_unretained 所暗示的那樣,具備非保留變量是危險的(由於它能夠懸掛),所以不鼓勵。兩個更好的選擇是使用 __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:
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];
};
複製代碼
可是,對於 non-trivial cycles,你應該使用:
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。然而,這對於 nontrivial cycles 來講變得不切實際,由於很難或不可能驗證 __unsafe_unretained 指針仍然有效而且仍然指向相同的對象。
使用 ARC,你沒法使用 NSAutoreleasePool 類直接管理自動釋放池。相反,你使用 @autoreleasepool 塊:
@autoreleasepool {
// Code, such as a loop that creates a large number of temporary objects.
}
複製代碼
這種簡單的結構容許編譯器推斷引用計數狀態。在進入時,推送自動釋放池。在正常退出(break,return,goto,fall-through 等)時,將彈出自動釋放池。爲了與現有代碼兼容,若是 exit 是由異常引發的,則不會彈出自動釋放池。
全部 Objective-C 模式都提供此語法。它比使用 NSAutoreleasePool 類更有效; 所以,咱們鼓勵你採用它代替使用 NSAutoreleasePool。
用於在 iOS 和 OS X 中聲明 outlets 的模式隨 ARC 而變化,而且在兩個平臺上變得一致。你應該採用的模式是:outlets 應該是弱的,除了從文件全部者到 nib 文件(或故事板場景)中應該很強的頂級對象的出口。
使用 ARC,如今使用 nil 隱式初始化 strong,weak 和 autoreleasing 棧變量。例如:
- (void)myMethod {
NSString *name;
NSLog(@"name: %@", name);
}
複製代碼
將爲 name 的值記錄 null,而不是崩潰。
使用新的 -fobjc-arc 編譯器標誌啓用 ARC。若是對某些文件使用手動引用計數更方便,也能夠選擇在每一個文件的基礎上使用 ARC。對於使用 ARC 做爲默認方法的項目,可使用該文件的新 -fno-objc-arc 編譯器標誌爲特定文件禁用 ARC。
Xcode 4.2 及更高版本的 OS X v10.6 及更高版本(64位應用程序)以及 iOS 4 及更高版本支持 ARC。OS X v10.6 和 iOS 4 不支持弱引用。Xcode 4.1 及更早版本中沒有 ARC 支持。
在許多 Cocoa 應用程序中,你須要使用 Core Foundation 樣式的對象,不管是來自 Core Foundation 框架自己(例如 CFArrayRef 仍是 CFMutableDictionaryRef),仍是來自採用 Core Foundation 約定的框架(如 Core Graphics)(你可使用相似 CGColorSpaceRef 和 CGGradientRef 的類型))。
編譯器不會自動管理 Core Foundation 對象的生命週期; 你必須根據 Core Foundation 內存管理規則調用 CFRetain 和 CFRelease(或相應的特定於類型的變體)。
若是在 Objective-C 和 Core Foundation 風格的對象之間進行轉換,則須要使用強制轉換(在 objc/runtime.h 中定義)或 Core Foundation 樣式宏(在 NSObject.h 中定義)來告訴編譯器對象的全部權語義:
__bridge 在 Objective-C 和 Core Foundation 之間傳輸指針,不轉讓全部權。
__bridge_retained 或 CFBridgingRetain 將一個 Objective-C 指針強制轉換爲 Core Foundation 指針,並將全部權轉移給你。
你有責任調用 CFRelease 或相關函數來放棄對象的全部權。
__bridge_transfer 或 CFBridgingRelease 將非 Objective-C 指針移動到 Objective-C,並將全部權轉移到 ARC。
ARC 負責放棄對象的全部權。
例如,若是你有這樣的代碼:
- (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);
}
複製代碼
編譯器理解返回 Core Foundation 類型的 Objective-C 方法遵循歷史 Cocoa 命名約定。例如,編譯器知道,在 iOS 中,UIColor 的 CGColor 方法返回的 CGColor 不歸屬。你仍必須使用適當的類型轉換,如此示例所示:
NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]];
[colors addObject:(id)[[UIColor lightGrayColor] CGColor]];
複製代碼
在函數調用中在 Objective-C 和 Core Foundation 對象之間進行轉換時,須要告訴編譯器有關傳遞對象的全部權語義。Core Foundation 對象的全部權規則是 Core Foundation 內存管理規則中指定的規則; Objective-C 對象的規則在 Advanced Memory Management Programming Guide 中指定。
在下面的代碼片斷中,傳遞給 CGGradientCreateWithColors 函數的數組須要適當的強制轉換。arrayWithObjects: 返回的對象的全部權不會傳遞給函數,所以強制轉換爲 __bridge。
NSArray *colors = <#An array of colors#>;
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations);
複製代碼
代碼片斷在如下方法實現中的上下文中示出。另請注意 Core Foundation 內存管理功能的使用,這些功能由 Core Foundation 內存管理規則決定。
- (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.
}
複製代碼
遷移現有項目時,你可能會遇到各類問題。如下是一些常見問題以及解決方案。
你沒法調用 retain,release 或 autorelease。
這是一個功能。你也寫不出來:
while ([x retainCount]) { [x release]; }
複製代碼
你不能調用 dealloc。
若是要在 init 方法中實現單例或替換對象,一般會調用 dealloc。對於單例,請使用共享實例模式。在 init 方法中,你沒必要再調用 dealloc,由於在覆蓋 self 時將釋放該對象。
你不能使用 NSAutoreleasePool 對象。
請改用新的 @autoreleasepool {} 結構。這會強制你的自動釋放池上的塊結構,而且比 NSAutoreleasePool 快約六倍。@autoreleasepool 甚至適用於非 ARC 代碼。由於 @autoreleasepool 比 NSAutoreleasePool 快得多,因此許多舊的「性能黑客」能夠簡單地用無條件的 @autoreleasepool 替換。
遷移器處理 NSAutoreleasePool 的簡單用法,但它沒法處理複雜的條件狀況,或者在新的 @autoreleasepool 的主體內定義變量並在其後使用的狀況。
ARC 要求你在 init 方法中將 [super init] 的結果分配給 self。
如下在 ARC init 方法中無效:
[super init];
複製代碼
簡單的解決方法是將其更改成:
self = [super init];
複製代碼
正確的解決方法是這樣作,並在繼續以前檢查結果爲 nil:
self = [super init];
if (self) {
...
複製代碼
你沒法實現自定義 retain 或 release 方法。
實現自定義 retain 或 release 方法會打破弱指針。想要提供自定義實現有幾個常見緣由:
性能。
請不要再這樣作了; NSObject 的 retain 和 release 的實現如今要快得多。若是你仍然發現問題,請提交錯誤。
實現自定義弱指針系統。
請改用 __weak。
實現單例類。
請改用共享實例模式。或者,使用類而不是實例方法,這樣就沒必要分配對象了。
「Assigned」實例變量變得 strong。
在 ARC 以前,實例變量是非擁有引用 - 直接將對象分配給實例變量並不延長對象的生命週期。爲了使屬性變強,你一般會實現或合成調用適當內存管理方法的訪問器方法; 相反,你可能已經實現瞭如下示例中顯示的訪問器方法來維護弱屬性。
@interface MyClass : Superclass {
id thing; // Weak reference.
}
// ...
@end
@implementation MyClass
- (id)thing {
return thing;
}
- (void)setThing:(id)newThing {
thing = newThing;
}
// ...
@end
複製代碼
對於 ARC,實例變量默認是強引用 - 將對象直接分配給實例變量會延長對象的生命週期。遷移工具沒法肯定實例變量什麼時候弱。 要保持與之前相同的行爲,必須將實例變量標記爲弱,或使用聲明的屬性。
@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
複製代碼
你不能在 C 結構中使用 strong ids。
例如,如下代碼將沒法編譯:
struct X { id x; float y; };
複製代碼
這是由於 x 默認 strong 引用,編譯器沒法安全地合成使其正常工做所需的全部代碼。例如,若是經過一些最終執行自由的代碼將指針傳遞給其中一個結構,則必須在釋放結構以前釋放每一個 id。編譯器沒法可靠地執行此操做,所以在 ARC 模式下不容許徹底禁用結構中的 strong ids。有幾種可能的解決方案:
使用 Objective-C 對象而不是結構。
不管如何,這被認爲是最佳實踐。
若是使用 Objective-C 對象是次優的(可能你須要這些結構的密集數組),那麼請考慮使用 void *。
這須要使用下面描述的顯式強制轉換。
將對象引用標記爲 __unsafe_unretained。
這種方法對於這樣的半常見模式可能頗有用:
struct x { NSString *S; int X; } StaticArray[] = {
@"foo", 42,
@"bar, 97,
...
};
複製代碼
你將結構聲明爲:
struct x { NSString * __unsafe_unretained S; int X; }
複製代碼
若是對象能夠從指針下面釋放出來,這多是有問題的而且是不安全的,可是對於已知永遠像常量字符串文字同樣的事物來講它很是有用。
你不能直接在 id 和 void * 之間進行轉換(包括 Core Foundation 類型)。
這在 Managing Toll-Free Bridging 中有更詳細的討論。
我如何看待 ARC?retains/releases 的位置在哪裏?
嘗試再也不考慮 retain/release 調用的位置,而是考慮應用程序算法。考慮對象中的「強弱」指針,對象全部權以及可能的引用循環。
我還須要爲個人對象編寫 dealloc 方法嗎?
也許。
因爲 ARC 不會自動執行 malloc/free,管理 Core Foundation 對象,文件描述符等的生命週期,所以你仍然能夠經過編寫 dealloc 方法來釋放這些資源。
你沒必要(實際上不能)釋放實例變量,但你可能須要在系統類和其餘未使用 ARC 編譯的代碼上調用 [self setDelegate:nil]。
ARC 中的 dealloc 方法不須要 - 或容許調用[super dealloc]; 連接到父類由運行時處理和強制執行。
ARC 中仍然有引用循環嗎?
是。
ARC 自動 retain/release,並繼承引用循環的問題。幸運的是,遷移到 ARC 的代碼不多開始泄漏,由於屬性已經聲明屬性是否 retaining。
blocks 如何在 ARC 中工做?
在 ARC 模式下向塊傳遞塊時塊「正常工做」,例如在返回中。你沒必要再調用 Block Copy。
須要注意的一件事是 NSString * __block myString 保留在 ARC 模式下,而不是可能懸空的指針。要獲取先前的行爲,請使用 __block NSString * __unsafe_unretained myString 或(更好的是)使用 __block NSString * __weak myString。
我可使用 Snow Leopard 爲 ARC 開發 OS X 應用程序嗎?
不能夠。Xcode 4.2 的 Snow Leopard 版本在 OS X 上根本不支持 ARC,由於它不包括 10.7 SDK。Snow Leopard 的 Xcode 4.2 確實支持 ARC for iOS,而 Xcode 4.2 for Lion 支持 OS X 和 iOS。這意味着你須要 Lion 系統來構建在 Snow Leopard 上運行的 ARC 應用程序。
我能夠在 ARC 下建立一個 retained 指針的C數組嗎?
是的,你能夠,如此示例所示:
// Note calloc() to get zero-filled memory.
__strong SomeClass **dynamicArray = (__strong SomeClass **)calloc(entries, sizeof(SomeClass *));
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);
複製代碼
有許多方面須要注意:
ARC 慢嗎?
這取決於你正在測量什麼,但一般是「不」。編譯器有效地消除了許多無關的 retain/release 調用,而且已經投入了大量精力來加速 Objective-C 運行時。特別是,當方法的調用者是 ARC 代碼時,常見的「返回 retain/autoreleased 對象」模式要快得多,而且實際上並不將對象放入自動釋放池中。
須要注意的一個問題是優化器不在常見的調試配置中運行,所以指望在-O0處看到比在-Os更多的 retain/release 流量。
ARC 是否在 ObjC++ 模式下工做?
是。你甚至能夠在類和容器中放置 strong/weak idsD。ARC 編譯器在複製構造函數和析構函數等中合成 retain/release 邏輯以使其工做。
哪些類不支持弱引用?
你當前沒法建立對如下類的實例的弱引用:
NSATSTypesetter,NSColorSpace,NSFont,NSMenuView,NSParagraphStyle,NSSimpleHorizontalTypesetter 和 NSTextView。
注意:此外,在 OS X v10.7 中,你沒法建立對 NSFontManager,NSFontPanel,NSImage,NSTableCellView,NSViewController,NSWindow 和 NSWindowController 實例的弱引用。此外,在 OS X v10.7中,AV Foundation 框架中的任何類都不支持弱引用。
對於聲明的屬性,你應該使用 assign 而不是 weak; 對於變量,你應該使用 __unsafe_unretained 而不是 __weak。
此外,你沒法在 ARC 下從 NSHashTable,NSMapTable 或 NSPointerArray 的實例建立弱引用。
在對 NSCell 或使用 NSCopyObject 的其餘類進行子類化時,我該怎麼辦?
沒什麼特別的。ARC 負責處理你必須明確添加額外 retains 的狀況。使用 ARC,全部複製方法都應該只複製實例變量。
我能夠選擇退出 ARC 以獲取特定文件嗎?
能夠。
遷移項目以使用 ARC 時,-fobjc-arc 編譯器標誌將設置爲全部 Objective-C 源文件的缺省值。你可使用該類的 -fno-objc-arc 編譯器標誌爲特定類禁用 ARC。在 Xcode 中,在目標 Build Phases 選項卡中,打開 Compile Sources 組以顯示源文件列表。雙擊要爲其設置標誌的文件,在彈出式面板中輸入 -fno-objc-arc,而後單擊「完成」。
是否在 Mac 上棄用了GC(垃圾收集)?
OS X Mountain Lion v10.8 中不推薦使用垃圾收集,而且將在 OS X 的將來版本中刪除垃圾收集。自動引用計數是推薦的替代技術。爲了幫助遷移現有應用程序,Xcode 4.3 及更高版本中的 ARC 遷移工具支持將垃圾收集的 OS X 應用程序遷移到 ARC。
注意:對於面向 Mac App Store 的應用,Apple 強烈建議你儘快使用 ARC 替換垃圾回收,由於 Mac App Store 指南禁止使用已棄用的技術。