ARC是一個(gè)編譯器特征,它提供了對(duì)OC對(duì)象自動(dòng)管理內(nèi)存。ARC讓開發(fā)者專注于感興趣的代碼和對(duì)象的關(guān)系,而不用考慮對(duì)象的retain和release。
概要
ARC在編譯時(shí)期添加代碼,保證對(duì)象可用。概念上說(shuō),ARC遵循手動(dòng)引用計(jì)數(shù)的規(guī)則,替開發(fā)者,在編譯時(shí)期添加合適的代碼。
為了讓編譯器生成正確的代碼,ARC限制使用某些方法和使用toll-free橋接。ARC為對(duì)象引用和聲明的屬性引入了新的生命周期描述符。
Xcode4.2(Mac OS 10.6、10.7和iOS4和iOS5)支持ARC,弱引用在10.6和iOS4上不支持。
Xcode提供了一個(gè)工具:自動(dòng)機(jī)械得轉(zhuǎn)化為ARC(比如移除retain和release的調(diào)用),并幫助開發(fā)者解決不能自動(dòng)遷移的問(wèn)題。遷移工具將所有文件轉(zhuǎn)化成ARC,開發(fā)者也可以對(duì)單個(gè)文件實(shí)施ARC,方便于開發(fā)者對(duì)某些文件手動(dòng)引用計(jì)數(shù)。
ARC概要
ARC評(píng)估了對(duì)象的生命周期,并自動(dòng)插入合適的代碼在編譯時(shí)期,從而代替開發(fā)者不得不考慮何時(shí)需要retain、release和autorelease。編譯器替開發(fā)者,生成合適的dealloc方法。一般來(lái)說(shuō),當(dāng)開發(fā)者需要在手動(dòng)引用計(jì)數(shù)和ARC配合使用時(shí)候,使用傳統(tǒng)ARC的Cocoa命名慣例是很重要的。
一個(gè)正確的完整的Person類如下:
@interface Person : NSObject
@property NSString *firstName;
@property NSString *lastName;
@property NSNumber *yearOfBirth;
@property Person *spouse;
@end
@implementation Person
@end
對(duì)象的屬性默認(rèn)是strong;strong屬性在 “ARC Introduces New Lifetime Qualifiers.”有描述
1 - (void)contrived {
3 ? ? Person *aPerson = [[Person alloc] init];
5 ? ? [aPerson setFirstName:@"William"];
7 ? ? [aPerson setLastName:@"Dudney"];
9 ? ? [aPerson setYearOfBirth:[[NSNumber alloc] initWithInteger:2011]];
11 ? ? NSLog(@"aPerson: %@", aPerson);
13 ? ?}
ARC掌管了內(nèi)存管理,所以Person和NSNumber不會(huì)泄露。
開發(fā)者還可以安全得實(shí)現(xiàn)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之前不會(huì)被銷毀。
ARC執(zhí)行了新的規(guī)則
ARC執(zhí)行了一些新的規(guī)則,是其他編譯模式?jīng)]有的。這個(gè)規(guī)則是:致力于提供一個(gè)安全可靠的內(nèi)存管理模式。在某些情況下,他們只是執(zhí)行最佳實(shí)踐;某些情況,他們簡(jiǎn)化你的代碼或者處理那沒明顯的不需要內(nèi)存問(wèn)題。如果你違反這些規(guī)則,立即得到一個(gè)編譯錯(cuò)誤,而不會(huì)在運(yùn)行顯示一個(gè)微妙的bug。
●?開發(fā)者不能顯式調(diào)用dealloc;不能實(shí)現(xiàn)和調(diào)用retain、release、retainCount和autorelease。
禁止使用@selector(retain),@selector(release)等等。
開發(fā)者仍可以實(shí)現(xiàn)dealloc方法,如果你想管理資源而不是變量。開發(fā)者不能release變量,但是可以調(diào)用[systemClassInstance? ? ? ? ? setDelegate:nil]在系統(tǒng)類上,或者其他不是用ARC編譯的代碼上。
ARC中自定義的dealloc方法,不需要調(diào)用[super dealloc](其實(shí)這樣做就會(huì)導(dǎo)致編譯錯(cuò)誤),編譯器會(huì)強(qiáng)制自動(dòng)鏈接到父類。
開發(fā)者仍可以對(duì)Core Foundation-style對(duì)象,使用CFRetain,CFRelease和其他相關(guān)方法。
● 不能使用NSAllocateObject或者NSDeallocateObject。開發(fā)者創(chuàng)建對(duì)象使用alloc,運(yùn)行時(shí)環(huán)境負(fù)責(zé)銷毀對(duì)象。
● 在C數(shù)據(jù)結(jié)構(gòu)中,不能使用對(duì)象指針。可以使用OC類來(lái)代替C的struct
● id和void*沒有自動(dòng)轉(zhuǎn)換.
開發(fā)者必須使用特殊的類型轉(zhuǎn)化。開發(fā)者需要通過(guò)函數(shù)參數(shù)傳遞,在OC對(duì)象和Core Foundation之間做類型轉(zhuǎn)換。
● 開發(fā)者不能使用NSAutoreleasePool對(duì)象。ARC下使用@autoreleasepool,它比NSAtuoreleasePool更有效率。
● 開發(fā)者不能使用內(nèi)存zones。不用再使用NSZone了。他們已經(jīng)被現(xiàn)代的OC運(yùn)行環(huán)境給忽略了。
為了配合手動(dòng)引用計(jì)數(shù),ARC的方法命名有限制:
● 訪問(wèn)器方法不能已new開頭,反過(guò)來(lái)就是:開發(fā)者不能聲明一個(gè)已new開頭的屬性,除非你給你指定一個(gè)getter方法
1 // Won't work:
2 @property NSString *newTitle;
3
4 // Works:
5 @property (getter=theNewTitle) NSString *newTitle;
6
ARC引入了新的Lifetime修飾符
ARC引入幾個(gè)新的修飾符和弱(weak)引用。弱引用不會(huì)延伸到對(duì)象生命周期,并自動(dòng)設(shè)置為nil,當(dāng)該對(duì)象沒有任何的強(qiáng)引用的時(shí)候。
開發(fā)者需要使用這些修飾來(lái)管理對(duì)象圖。通常ARC不對(duì)循環(huán)引用做警告。謹(jǐn)慎的使用弱引用可以保證不會(huì)循環(huán)引用。
Property屬性
weak和strong關(guān)鍵字作為新的property屬性被引入,例如:
1
2 @property(strong)?MyClass?*myObject;
3
4
5 //?except?that?if?the?MyClass?instance?is?deallocated,
6
7 @property(weak)?MyClass?*myObject;
ARC下,strong是默認(rèn)property屬性
變量的修飾符
開發(fā)者使用下面得lifetime描述符。
__strong
__weak
__unsafe_unretained
__autoreleasing
● 默認(rèn)是__strong。只要對(duì)象還有強(qiáng)引用,該對(duì)象“活著”。
● __weak不保留對(duì)象,只是簡(jiǎn)單引用。weak對(duì)象將被設(shè)置nil,當(dāng)對(duì)象沒有任何強(qiáng)引用的時(shí)候。
● __unsafe_unretained 不保留對(duì)象,只是簡(jiǎn)單引用。但是不設(shè)置為nil,當(dāng)對(duì)象沒有任何強(qiáng)引用得時(shí)候。如果對(duì)象被銷毀,? __unsafe_unretained的對(duì)象將會(huì)野指針。
● __autoreleasing 用于標(biāo)識(shí)id*的引用參數(shù),或者需要自動(dòng)釋放的返回的對(duì)象。
開發(fā)者需要正確修飾變量。使用下面的格式來(lái)修飾變量聲明。
類名* ?修飾 ?變量名 (ClassName * qualifier variableName;)
例如:
1 MyClass?*?__weak?myWeakReference;
2 MyClass?*?__unsafe_unretained?myUnsafeReference;
其他的變種在技術(shù)上是不正確的,但可能可以通過(guò)編譯。了解更多http://cdecl.org/
在棧上小心使用__weak。考慮下面的代碼:
1 NSString?*?__weak?string?=?[[NSString?alloc]?initWithFormat:@ "First?Name:?%@" ,?[self?firstName]];
2 NSLog(@ "string:?%@" ,?string);
盡管string在初始化后被使用了。但是,由于在賦值的時(shí)候沒有強(qiáng)引用;因此它將立即被銷毀。
開發(fā)者同樣需要注意傳遞引用的地方,例如下面的代碼:
1 NSError?*error;
2 BOOL?OK?=?[myObject?performOperationWithError:&error];
3 if ?(!OK)?{
4 ???? //?Report?the?error.
5 ???? //?...
然而,這種錯(cuò)誤是隱含的。
1 NSError?*?__strong?e;
并且聲明的方法可能是下面這樣:
1 -(BOOL)performOperationWithError:(NSError?*?__autoreleasing?*)error;
編譯器將重寫代碼:
1 NSError?*?__strong?error;
2 NSError?*?__autoreleasing?tmp?=?error;
3 BOOL?OK?=?[myObject?performOperationWithError:&tmp];
4 error?=?tmp;
5 if ?(!OK)?{
6 ???? //?Report?the?error.
7 ???? //?...
本地變量聲明(__strong)和參數(shù)(__autoreleasing)導(dǎo)致編譯器創(chuàng)建臨時(shí)變量。當(dāng)開發(fā)者對(duì)__strong對(duì)象取地址,將參數(shù)聲明為id __strong*,就得到原始的指針?;蛘唛_發(fā)者可以將變量聲明為__autoreleasing
使用Lifetime修飾符,避免循環(huán)引用
開發(fā)者可以通過(guò)lifetime修飾符來(lái)避免循環(huán)引用。例如,如果你有一個(gè)對(duì)象圖(關(guān)于父-子繼承)。并且父類需要引用子類,相反子類也要用。這時(shí)候,開發(fā)者把parent-to-child寫做strong并把child-to-parent關(guān)系寫作weak。其他情況可能有些麻煩,特別是調(diào)用block變量的時(shí)候。
手動(dòng)引用計(jì)數(shù)模式下,__block id x 這樣的寫法,不會(huì)對(duì)x進(jìn)行retain。在ARC模式,__block id x;默認(rèn)retain x(就像其他變量一樣)。如果想在ARC模式下,得到手動(dòng)引用計(jì)數(shù)的效果,開發(fā)者可以使用__unsafe_unretained __block id x。顧名思義,__unsafe_unretained __block id x是危險(xiǎn)的(因?yàn)樗赡軐?dǎo)致野指針)因此也不建議使用。好的解決方案是:使用__weak或者將__block的值設(shè)置為nil,來(lái)打斷retain循環(huán)。
下面的代碼段展示了如何使用手動(dòng)引用計(jì)數(shù)
MyViewController *myController = [[MyViewController alloc] init…];
// ...
myController.completionHandler =? ^(NSInteger result) {
[myController dismissViewControllerAnimated:YES completion:nil];
};
[self presentViewController:myController animated:YES completion:^{
[myController release];
}];
正如說(shuō)的那樣,開發(fā)者可以使用__block修飾符并且設(shè)置myController變量為nil,在完成處理的時(shí)候。
1 MyViewController * __block myController = [[MyViewController alloc] init…];
2 // ...
3 myController.completionHandler =? ^(NSInteger result) {
4 ? ? [myController dismissViewControllerAnimated:YES completion:nil];
5 ? ? myController = nil;
6 };
或者,你可以使用臨時(shí)的__weak變量。下面是一個(gè)簡(jiǎn)單的實(shí)現(xiàn)
1 MyViewController *myController = [[MyViewController alloc] init…];
2 // ..
3 MyViewController * __weak weakMyViewController = myController;
4 myController.completionHandler =? ^(NSInteger result) {
1 ? ? [weakMyViewController dismissViewControllerAnimated:YES completion:nil];
1 };
1 ? 對(duì)于non-trivial循環(huán),開發(fā)者應(yīng)該使用下面代碼:
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...
}
};
在某些情況,開發(fā)者使用__unsafe_unretained,如果類本身不是__weak修飾。然而,這樣將變得不切合實(shí)際了,因?yàn)樗赡芎茈y或者不可能去驗(yàn)證:__unsafe_unretained的指針仍然可用并且指向某些變量。
ARC使用一個(gè)新語(yǔ)句管理Autorelease Pools
使用ARC,開發(fā)者不能直接使用NSAutoreleasePool來(lái)管理autorelease pools。而使用@autoreleasepool代替它。
@autoreleasepool {
// Code, such as a loop that creates a large number of temporary objects.
}
這個(gè)簡(jiǎn)單的結(jié)構(gòu)允許編譯器思考引用計(jì)數(shù)的狀態(tài)。進(jìn)入的時(shí)候,自動(dòng)釋放池被push。在正常退出的時(shí)候自動(dòng)釋放池配poped出來(lái)。為了配合現(xiàn)有代碼,如果代碼異常退出,自動(dòng)釋放池將不會(huì)pop出來(lái)。它比NSAutoreleasePool更有效率;因此建議開發(fā)者替換NSAtuoreleasePool。
管理Outlet的模式在各個(gè)平臺(tái)變得一致
在iOS和OS X聲明Outlet的模式在ARC中發(fā)生改變,并且在兩個(gè)平臺(tái)上變的一致,你應(yīng)該采用的模式是:outlet修飾符應(yīng)該是weak,除了那些從File’s owner到nib文件( 或者storyBoard場(chǎng)景)的高級(jí)對(duì)象,他們應(yīng)該是強(qiáng)引用。
棧變量被初始化為nil
使用ARC,strong、weak和autoreleasing棧變量將會(huì)隱式的初始化為nil,例如:
- (void)myMethod {
NSString *name;
NSLog(@"name: %@", name);
}
將打印出null,而不是崩潰。
使用編譯器選項(xiàng)來(lái)開啟和關(guān)閉ARC
開發(fā)者使用-fobjc-arc 編譯選項(xiàng)開啟ARC,還可以對(duì)某一個(gè)文件使用ARC,便于在使用手動(dòng)引用計(jì)數(shù)的文件中使用ARC。對(duì)于已經(jīng)使用ARC的工程,仍可以指定一個(gè)文件來(lái)關(guān)閉ARC通過(guò)-fno-objc-arc編譯選項(xiàng)。
管理Toll-Free Bridging
在多數(shù)的Cocoa程序中,開發(fā)者需要使用Core Foundaton-style對(duì)象,無(wú)論是從Core Foundation框架還是從Core foundation的其他框架比如Core Graphics。
編譯器不會(huì)自動(dòng)管理Core foundation對(duì)象的生命周期。開發(fā)者必須根據(jù)COreFoundation的內(nèi)存管理規(guī)則,使用CFRetain和CFRelease。
如果開發(fā)者在OC和Core foundation兩種對(duì)象做轉(zhuǎn)換,需要告訴編譯器對(duì)象的所有權(quán)。
* __bridge: 只做類型轉(zhuǎn)化,不修改相關(guān)對(duì)象的引用計(jì)數(shù),原來(lái)的Core Foundation對(duì)象在不用時(shí),需要調(diào)用CFRelease方法
* __bridge_retained(CFBridgingRetain): 類型轉(zhuǎn)化后,將相關(guān)對(duì)象的引用計(jì)數(shù)+1,原來(lái)的Core Foundation對(duì)象在不用時(shí),需要調(diào)用CFRelease方法。
* __bridge_transfer: 類型轉(zhuǎn)換后,將該對(duì)象的引用計(jì)數(shù)交給ARC管理,Core Foundation對(duì)象在不用時(shí),不在需要調(diào)用CFRelease方法。
例如,現(xiàn)有代碼:
- (void)logFirstNameOfPerson:(ABRecordRef)person {
NSString *name = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSLog(@"Person's first name: %@", name);
[name release];
}
開發(fā)用下面的代碼代替
1 - (void)logFirstNameOfPerson:(ABRecordRef)person {
2
3 ? ? NSString *name = (NSString *)CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
3 ? ? NSLog(@"Person's first name: %@", name);
1 }
2
編譯器處理從COcoa方法返回的 CF 對(duì)象
編譯器知道返回Core foundaion類的OC的方法,遵循歷史的規(guī)定。例如,編譯器知道從UIColor的CGColor方法返回的GCColor是不擁有的。開發(fā)者必須使用合適的類型去轉(zhuǎn)化。例如:
NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]];
[colors addObject:(id)[[UIColor lightGrayColor] CGColor]];
使用所有權(quán)關(guān)鍵字轉(zhuǎn)化函數(shù)參數(shù)
當(dāng)開發(fā)者在OC和Core foundation的對(duì)象之間轉(zhuǎn)化時(shí),需要告訴編譯器傳遞object的所有權(quán)。Core foundation對(duì)象所有權(quán)的規(guī)則在CoreFoundation的內(nèi)存管理規(guī)則中。OC的所有權(quán)規(guī)則在Advanced Memory Management Programming Guide中。
下面的代碼段,數(shù)組傳遞給CGGradientCreateWithCorlors函數(shù)需要一個(gè)合適的轉(zhuǎn)化。數(shù)組是arrayWithObjects返回的,所以,不要將所有權(quán)傳遞給函數(shù),因此使用__bridge
NSArray *colors = <#An array of colors#>;
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations);
下面代碼段實(shí)現(xiàn)了一個(gè)context,使用Core Foundation內(nèi)存管理的方法。
1 - (void)drawRect:(CGRect)rect {
1 ? ? CGContextRef ctx = UIGraphicsGetCurrentContext();
2 ? ? CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
7 ? ? CGFloat locations[2] = {0.0, 1.0};
1 ? ? NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]];
2 ? ? [colors addObject:(id)[[UIColor lightGrayColor] CGColor]];
2 ? ? CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations);
4 ? ? CGColorSpaceRelease(colorSpace);? // Release owned Core Foundation object.
6 ? ? CGPoint startPoint = CGPointMake(0.0, 0.0);
1 ? ? CGPoint endPoint = CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMaxY(self.bounds));
2 ? ? CGContextDrawLinearGradient(ctx, gradient, startPoint, endPoint,
1 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
3 ? ? CGGradientRelease(gradient);? // Release owned Core Foundation object.
5 }
將工程轉(zhuǎn)化為ARC,遇到的常見問(wèn)題
當(dāng)遷移現(xiàn)有的項(xiàng)目,你可能會(huì)遇到的各種問(wèn)題。這里有一些共同的問(wèn)題,共同解決方案。
● 不能調(diào)用retain,release或者autorelease,這是一種特性,甚至不可以這么寫:
? while ([x retainCount]) { [x release]; }
● 不能調(diào)用dealloc
通常,開發(fā)者在單例的實(shí)現(xiàn)或者替換一個(gè)對(duì)象的init方法的時(shí)候調(diào)用dealloc。對(duì)于單例模式,使用共享實(shí)例模式。在init方法中,你不用調(diào)用dealloc,因?yàn)閷?duì)象會(huì)被釋放,當(dāng)重寫self的時(shí)候。
● 不能使用NSAutoreleasePool對(duì)象
表格@autoreleasepool{}代替NSAutoreleasePool.這將強(qiáng)制一個(gè)block處于一個(gè)自動(dòng)釋放池中。它比NSAutoreleaePool快6倍。@autoreleasepool也在在非ARC模式下工作。
● ARC需要開發(fā)者對(duì)[super init]賦值給self在init方法中。
下面代碼是不可行的
1 [super init];
簡(jiǎn)單的修正是:
self = [super init];
最合適的修復(fù)是這樣的,在初始化之前先檢測(cè)結(jié)果是不是nil。
? self = [super init];
? if (self) {
? ? ...
● 不能實(shí)現(xiàn)retain和release方法。
實(shí)現(xiàn)自定義的retain和release方法打破弱指針。提供了幾個(gè)常用的 “實(shí)現(xiàn)自定義”的原因。
1.性能
不要這么做,NSObject的retain和release已經(jīng)很快了。如果你發(fā)現(xiàn)仍有問(wèn)題,請(qǐng)?zhí)岢鲞@個(gè)bug
2.實(shí)現(xiàn)一個(gè)自定義的弱指針系統(tǒng)
使用__weak代替
3.實(shí)現(xiàn)單例
使用shared instance pattern代替?;蛘呤褂妙悂?lái)代替方法,避免分配對(duì)象。
● assigned 將變成strong
在ARC之前,變量的assigned的不會(huì)延伸到對(duì)象的生命周期。為了讓property變成強(qiáng)引用,開發(fā)者通常實(shí)例化或者synthesized訪問(wèn)器方法,里面是內(nèi)存管理方法。相比之下,你可以這樣實(shí)現(xiàn)訪問(wèn)器方法:
1 @interface MyClass : Superclass {
2 ? ? id thing; // Weak reference.
1 }
3 // ...
1 @end
1 @implementation MyClass
3 - (id)thing {
1 ? ? return thing;
2 }
3
4 - (void)setThing:(id)newThing {
5 ? ? thing = newThing;
1 }
9 // ...
1 @end
1 ARC下,實(shí)例中的變量默認(rèn)是strong引用,assigning一個(gè)對(duì)象給實(shí)例中的變量延伸到對(duì)象的生命周期。遷移工具不能決定一個(gè)實(shí)例變量即將weak。保持相同的行為之前,你必須標(biāo)記實(shí)例變量是weak,或聲明它的property
1 @interface MyClass : Superclass {
2
3 ? ? id __weak thing;
4
5 }
6
7 // ...
8
9 @end
10
1
2 @implementation MyClass
3
4 - (id)thing {
5
6 ? ? return thing;
7
8 }
9
10 - (void)setThing:(id)newThing {
11
12 ? ? thing = newThing;
13
14 }
15
16 // ...
17
18 @end
19
或者
1 @interface MyClass : Superclass
2 @property (weak) id thing;
3 // ...
4 @end
5
6 @implementation MyClass
7 @synthesize thing;
8 // ...
9 @end
10
● 不能使用strong ids在c的數(shù)據(jù)結(jié)構(gòu)
例如,下面的c結(jié)構(gòu)將不能編譯過(guò)
1 struct X { id x; float y; };
這是因?yàn)閤默認(rèn)是strong retain,但是,在正常運(yùn)行情況下,編譯器不能安全的合成所有需要的代碼。比如:如果你傳遞一個(gè)指針給x或者y后,執(zhí)行了free,每一個(gè)id將被release掉,在struct被free之前。編譯器不能可靠的做這些。所以strong ids在結(jié)構(gòu),在ARC中完全不允許。下面是一些解決方案:
1.用OC類代替c結(jié)構(gòu)。這應(yīng)該是最好的解決辦法。
2.如果使用OC類是次要的方法(可能你想要一個(gè)高密度的結(jié)構(gòu)數(shù)組),那么考慮使用void*代替。這需要使用顯示的轉(zhuǎn)化。
3.把對(duì)象引用作為__unsafe_unretained。這種方法是半常見的模式,這樣是有用的。
struct x { NSString *S;? int X; } StaticArray[] = {
@"foo", 42,
@"bar, 97,
...
};
開發(fā)者這樣聲明
1 struct x { NSString * __unsafe_unretained S; int X; }
這可能是有問(wèn)題的,如果對(duì)象可以被釋放時(shí)指針是不安全的,但它是非常有用的東西,被稱為是字符串常量。
● 不能直接將id和void*進(jìn)行轉(zhuǎn)化(包含Core Foundation類型)參考Managing Toll-Free Bridging
經(jīng)常遇到的問(wèn)題
我該怎樣認(rèn)識(shí)ARC?它在哪兒放置retains/releases。
不要想什么地方調(diào)用retain/release,考慮程序本身算法吧??紤]"strong and weak"關(guān)系,對(duì)象的所有權(quán)關(guān)系和可能存在的循環(huán)引用。
我還需要寫dealloc方法么
可能需要。因?yàn)锳RC不會(huì)自動(dòng)對(duì) Core Foundation 對(duì)象,文件描述符等等進(jìn)行malloc/free,,這些資源扔需要寫dealloc方法。
不能release對(duì)象的變量,但是可以調(diào)用[self setDelegate:nil]在系統(tǒng)的類和其他不用ARC的代碼。
ARC種 不需要dealloc方法,或者[super dealloc];在運(yùn)行時(shí)系統(tǒng)調(diào)用super代碼。
在ARC種,仍存在循環(huán)引用?
是的。ARC自動(dòng)retain/release并可能繼承了循環(huán)引用的問(wèn)題。幸運(yùn)的是:遷移到ARC的代碼很少泄露,因?yàn)闊o(wú)論properties是不是retain的,都被被聲明為retain了。
在ARC種blocks是如何工作的
Block能正常工作,當(dāng)你在棧上傳遞的時(shí)候,比如作為返回值。你無(wú)需block copy了。當(dāng)你傳遞block在棧下面的時(shí)候,添加到arrayWithObjects等需要retain的地方,需要使用[^{ }copy]。
有一件事情需要清除:NSString *__block myString是retain在ARC模式種,不可能是野指針。為了得到以前的行為,使用__block NSString *__unsafe_unretained myString 或者使用__block NSString *__weak myString.
我可以在雪豹OS種開發(fā)中使用ARC么?
不行。雪豹版本的Xcode4.2不支持ARC。
ARC下,可以創(chuàng)建C語(yǔ)言的retain的指針數(shù)組么
可以
1 // Note calloc() to get zero-filled memory.
2
3 __strong SomeClass **dynamicArray = (__strong SomeClass **)calloc(entries, sizeof(SomeClass *));
4
5 for (int i = 0; i < entries; i++) {
6
7 ? ? dynamicArray[i] = [[SomeClass alloc] init];
8
9 }
10
11
12
13 // When you're done, set each entry to nil to tell ARC to release the object.
14
15 for (int i = 0; i < entries; i++) {
16
17 ? ? dynamicArray[i] = nil;
18
19 }
20
21 free(dynamicArray);
22
下面是一些注意的地方:
● 你要寫__strong SomeClass **在某些情況,默認(rèn)情況是__autoreleasing SomeClass **.
● 開辟的內(nèi)存必須是零填充
● 需要設(shè)置每一項(xiàng)為nil在釋放array的時(shí)候(memset和bzero不好使的)
ARC慢么?
取決于你怎么測(cè)量,通常是不慢。編譯器消除很多無(wú)關(guān)緊要的retain/release調(diào)用。投入很大的努力在加快OC下的運(yùn)行環(huán)境。尤其是返回一個(gè)retian/autoreleased對(duì)象,ARC并不是真正將它放到自動(dòng)釋放池。
有一件事需要清除:優(yōu)化器不在debug模式下。所以想看到更多的retain/release的調(diào)用,使用-O0比-Os
ARC在ObjC++模式下工作么?
是的,甚至可以將strong/weakids在類和容器中。ARC編譯器合成retain/release邏輯在拷貝構(gòu)造函數(shù)和析構(gòu)函數(shù)鐘。
哪些類不支持weak引用?
下面的類不能創(chuàng)建弱引用:
NSATSTypesetter, NSColorSpace, NSFont, NSMenuView, NSParagraphStyle, NSSimpleHorizontalTypesetter, and NSTextView.
對(duì)于聲明properties時(shí),你應(yīng)該使用retain代替weak。對(duì)于變量你應(yīng)該使用__unsafe_unretained代替__weak.另外,你不能創(chuàng)建這些類的弱引用:NSHashTable, NSMapTable, or NSPointerArray
對(duì)NSCell和其他類使用NSCopyObject時(shí)候。
沒什么特別的。ARC負(fù)責(zé)的顯示retain的場(chǎng)景。ARC模式下,所有的copy方法應(yīng)該僅僅copy實(shí)例變量。
我可以對(duì)某個(gè)文件不使用ARC么?
是的。當(dāng)開發(fā)者遷移工程到ARC時(shí),對(duì)所有OC源文件設(shè)置為-fobjc-arc編譯選項(xiàng)。開發(fā)者可以指定一個(gè)文件設(shè)置-fno-objc-arc編譯選項(xiàng)。
GC(Grabage Collection)在mac上過(guò)時(shí)了?
Grabage Collection在10.8上已經(jīng)過(guò)時(shí),將來(lái)會(huì)重OS X中移除。ARC將是收推薦的替代技術(shù)。為了幫助遷移現(xiàn)有程序,ARC遷移工具在Xcode >=4.3 支持將GC遷移到ARC。