自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一篇文章徹底弄清ARC始末

移動(dòng)開發(fā) iOS
Xcode提供了自動(dòng)化的工具,完成ARC轉(zhuǎn)換過程中需要手工操作的部分(例如刪除retain和release方法調(diào)用),并且?guī)椭阍谶w移過程中不能自動(dòng)完成的操作(選擇Edit->Refactor->Convert to Objective-C ARC)。遷移工具將工程中的所有文件使用ARC進(jìn)行轉(zhuǎn)換。如果你覺得在某些文件中使用手動(dòng)引用計(jì)數(shù)會(huì)更方便,那么你也可以選擇在單獨(dú)文件中使用ARC。

自動(dòng)引用計(jì)數(shù)(ARC)是編譯器的一個(gè)特色,提供了Objective-C對象的自動(dòng)內(nèi)存管理機(jī)制。比起不得不考慮retain和release操作,ARC讓你更加專注于應(yīng)用中那些有趣的代碼,如對象圖,對象關(guān)系。

摘要(Summary)

通過在編譯期添加代碼的方式,ARC保證所有對象按需存在,按需釋放。從概念上來講,它與手動(dòng)引用計(jì)數(shù)(參見 Advanced Memory Management Programming Guide)有著相同的內(nèi)存管理約定,二者都會(huì)為你添加合適的內(nèi)存管理方法調(diào)用。 為了編譯器能生成正確的代碼,ARC限定了你可以使用的一些方法,以及toll-free橋接的使用方式(參見 “Toll-Free Bridged Types”).與此同時(shí)ARC還為對象引用(object references )和聲明式屬性(declared properties)引進(jìn)了新的生命周期限定符(lifetime qualifiers )。 ARC適用于OS X v10.6和v10.7(64位)下的Xcode4.2,以及IOS 4和IOS5.OS X v10.6和IOS4不支持弱引用。Xcode提供了自動(dòng)化的工具,完成ARC轉(zhuǎn)換過程中需要手工操作的部分(例如刪除retain和release方法調(diào)用),并且?guī)椭阍?遷移過程中不能自動(dòng)完成的操作(選擇Edit->Refactor->Convert to Objective-C ARC)。遷移工具將工程中的所有文件使用ARC進(jìn)行轉(zhuǎn)換。如果你覺得在某些文件中使用手動(dòng)引用計(jì)數(shù)會(huì)更方便,那么你也可以選擇在單獨(dú)文件中使用ARC。
參見:
Advanced Memory Management Programming Guide
Memory Management Programming Guide for Core Foundation

ARC概述(ARC Overview)

ARC會(huì)評估對象所需的生命期,并會(huì)在編譯期為你自動(dòng)插入合適的內(nèi)存管理調(diào)用方法,取代之前你不得不考慮何時(shí)需要使用 retain, release以及 autorelease的操作方式。編譯器也會(huì)為你生成合適的 dealloc方法??偟膩碚f,如果你僅使用ARC,傳統(tǒng)的Cocoa命名規(guī)范只會(huì)在你需要與使用手動(dòng)引用計(jì)數(shù)的代碼交互時(shí)才是重要的。一個(gè)完整正確的Person類的實(shí)現(xiàn)看起來可能是這樣的:

  1. @interface Person : NSObject 
  2. @property NSString *firstName; 
  3. @property NSString *lastName; 
  4. @property NSNumber *yearOfBirth; 
  5. @property Person *spouse; 
  6. @end 
  7. @implementation Person 
  8. @end

(對象屬性(properties)默認(rèn)是強(qiáng)類型的( strong); strong屬性描述于 “ARC Introduces New Lifetime Qualifiers.”)
使用ARC,你可以如下實(shí)現(xiàn)一個(gè) contrived方法:

  1. - (void)contrived 
  2.     Person *aPerson = [[Person alloc] init]; 
  3.     [aPerson setFirstName:@"William"]; 
  4.     [aPerson setLastName:@"Dudney"]; 
  5.     [aPerson setYearOfBirth:[[NSNumber alloc] initWithInteger:2011]]; 
  6.     NSLog(@"aPerson: %@", aPerson); 

ARC會(huì)維護(hù)內(nèi)存管理,所以 Person和 NSNumber對象都不會(huì)泄露。
你也可以安全的實(shí)現(xiàn) Person類中的 takeLastnameFrom:方法。

  1. - (void)takeLastNameFrom:(Person *)person { 
  2.     NSString *oldLastname = [self lastName]; 
  3.     [self setLastName:[person lastName]]; 
  4.     NSLog(@"Lastname changed from %@ to %@", oldLastname, [self lastName]); 

ARC保證 oldLastName在 NSLog語句之前不會(huì)被釋放。
【ARC強(qiáng)制執(zhí)行新規(guī)則】(ARC Enforces New Rules)
為了正常運(yùn)轉(zhuǎn),ARC使用了一些在使用其它編譯模式下沒有的新規(guī)則。這些規(guī)則意在提供完全可靠的內(nèi)存管理模型;在某些情況下,它們僅使用***實(shí)踐方法,在其它情況下,它們僅簡化你的代碼或明顯的做出推論告知你不需要處理內(nèi)存管理。如果
你違反了這些規(guī)則,你會(huì)馬上得到一個(gè)編譯期錯(cuò)誤,而不是在運(yùn)行期可能會(huì)顯現(xiàn)的一個(gè)狡猾的bug。
1.不能顯示的調(diào)用dealloc,實(shí)現(xiàn)或調(diào)用 retain, release, retainCount,或 autorelease。
同樣也不要能使用 @selector(retain), @selector(release), 等等類似的選擇器。
如果你需要管理資源而不是釋放實(shí)例變量,那你可以實(shí)現(xiàn) dealloc方法。你不需要(事實(shí)上你不能)釋放實(shí)例變量,但你可能需要在系統(tǒng)類和其它的未使用ARC代碼中調(diào)用 [systemClassInstance setDelegate:nil] 方法。
在ARC中自定義的 dealloc方法不要調(diào)用 [super dealloc]方法(它實(shí)際上會(huì)導(dǎo)致編譯器錯(cuò)誤)。到super的鏈?zhǔn)秸{(diào)用是自動(dòng)的并且是編譯器強(qiáng)制執(zhí)行的。
你仍可以在Core Foundation樣式的的對象上,使用 CFRetain, CFRelease,和其它相關(guān)的函數(shù)。
2.你不能使用 NSAllocateObject 或 NSDeallocateObject
你使用 alloc來創(chuàng)建對象;運(yùn)行時(shí)系統(tǒng)會(huì)注意釋放這些對象。
3.你不能在C語言結(jié)構(gòu)體中使用對象指針。 與其使用一個(gè)結(jié)構(gòu)體( struct),不如創(chuàng)建一個(gè)Objective-C類來管理數(shù)據(jù)。
4. id與 void*之間不能隨意轉(zhuǎn)換
你必須使用特定的類型轉(zhuǎn)換來告訴編譯器對象的生命周期。你需要在Objective-C對象和以函數(shù)參數(shù)傳入的Core Foundation類型值之間進(jìn)行這樣的轉(zhuǎn)換。有關(guān)詳情,參見 “Managing Toll-Free Bridging”。
5.你不能使用 NSAutoreleasePool對象
ARC 提供了 @autoreleasepool來代替。這比 NSAutoreleasePool更高效。
6.你不能使用內(nèi)存區(qū)(memory zones)。
再也沒有使用 NSZone的必要了——現(xiàn)代的Obj-C運(yùn)行時(shí)會(huì)永遠(yuǎn)忽略它。
為了允許與自動(dòng)retain-release的代碼進(jìn)行交互,ARC在方法命名上加上了一個(gè)約束:
你不能以 new為開頭命名一個(gè)訪問器的名字。這反過來意味著你不必聲明一個(gè)以new開頭的屬性,除非你指定一個(gè)不同名稱的getter方法:

  1. // Won't work: 
  2. @property NSString *newTitle; 
  3. // Works: 
  4. @property (getter=theNewTitle) NSString *newTitle; 

【ARC引入新的生命周期限定符】(ARC Introduces New Lifetime Qualifiers)
ARC為對象引入了幾種新的生命周期限定符,以及弱類型引用( weak references)。弱類型應(yīng)用不會(huì)延長它所指向?qū)ο蟮纳芷?,一旦對象沒有強(qiáng)引用指向?qū)ο髸r(shí),弱引用會(huì)自動(dòng)變?yōu)? nil
在程序中,你應(yīng)該充分利用這些限定符來管理對象圖。尤其是,ARC不能阻止強(qiáng)引用循環(huán)(strong reference cycles,之前稱為retain cycles,參見“Practical Memory Management”)的發(fā)生。審慎的使用弱類型關(guān)系會(huì)幫助你避免創(chuàng)建強(qiáng)引用循環(huán)。
【Property的屬性】(Property Attributes)
weak和 strong關(guān)鍵字是新引入的property聲明屬性,如下例所示:

  1. // 以下聲明等價(jià)于 @property(retain) MyClass *myObject; 
  2. @property(strong) MyClass *myObject; 
  3. // 以下聲明等價(jià)于"@property(assign) MyClass *myObject;" 
  4. // 不同之處在于如果MyClass的實(shí)例變量釋放時(shí),其屬性值會(huì)設(shè)置為nil,而不會(huì)保存為一個(gè)野指針 
  5. @property(weak) MyClass *myObject; 

ARC下,對象類型的聲明默認(rèn)為 strong
【變量限定符】(Variable Qualifiers)
你可以向使用其它變量的限定符那樣,比如說, const,來使用以下生命周期限定符,

  1. __strong 
  2. __weak 
  3. __unsafe_unretained 
  4. __autoreleasing 

__strong是默認(rèn)的。只要有強(qiáng)類型指針指向一個(gè)對象,那么該對象會(huì)一直”生存“下去。
__weak表明一個(gè)不會(huì)維持所持對象生命期的引用。當(dāng)沒有強(qiáng)引用指向該對象時(shí),弱引用會(huì)設(shè)置為nil。
__unsafe_unretained指定一個(gè)引用,該引用不會(huì)維持所持對象的生命期,并且在沒有強(qiáng)引用指向?qū)ο髸r(shí)也不會(huì)設(shè)置為nil。如果它所指向的對象已經(jīng)被釋放,那么它會(huì)成為一個(gè)野指針。
__autoreleasing 用以指示以引用(id*)傳入的參數(shù)并在retun后自動(dòng)釋放。
你應(yīng)該正確的修飾變量。在對象變量的聲明時(shí)使用限定符的正確格式為:

  1. ClassName * qualifier variableName; 

例如:

  1. MyClass * __weak myWeakReference; 
  2. MyClass * __unsafe_unretained myUnsafeReference; 

從技術(shù)上講其它的變體寫法都是錯(cuò)誤的,但編譯器都會(huì)”寬恕“它們。要弄清該問題,參見http://cdecl.org/.
在堆棧上使用 __weak變量時(shí)要當(dāng)心??紤]以下的例子:

  1. NSString * __weak string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]]; 
  2. NSLog(@"string: %@", string); 

雖然 string是在初始化賦值之后使用,但是在賦值的時(shí)候并沒有其它強(qiáng)引用指向字符串對象;因此字符串對象會(huì)馬上釋放掉。log語句顯示 stirng的值為 null。(編譯器對這種情況會(huì)提示警告)
你也要注意通過引用方式傳入的對象。以下代碼會(huì)正常運(yùn)轉(zhuǎn)

  1. NSError *error; 
  2. BOOL OK = [myObject performOperationWithError:&error]; 
  3. if (!OK) { 
  4.     // Report the error. 
  5.     // ... 

而error的聲明是隱式的:

  1. NSError * __strong e; 

方法的聲明通常是: 

  1. -(BOOL)performOperationWithError:(NSError * __autoreleasing *)error; 

因此編譯器會(huì)重寫代碼:

  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)之間的區(qū)別導(dǎo)致編譯器創(chuàng)建臨時(shí)變量。在獲取__strong變量的地址時(shí)你可以通過將參數(shù)聲明為 id __storng*來獲得其原始指針?;蛘吣憧梢詫⒆兞柯暶鳛? __autoreleasing。


不要走開,下頁內(nèi)容更勁爆

#p#

【使用生命周期限定符來避免強(qiáng)類型循環(huán)引用】(Use Lifetime Qualifiers to Avoid Strong Reference Cycles)
你可以使用生命周期限定符來避免強(qiáng)類型循環(huán)引用。例如,通常如果你的對象圖形成于父-子層級結(jié)構(gòu)中,父對象需要引用它的子對象,反之亦然, 那么你構(gòu)造parent-to-child的關(guān)系為強(qiáng)類型,child-to-parent的關(guān)系為弱類型。其它情況可能會(huì)更加微妙,尤其是在涉及到 block對象時(shí)。
在手動(dòng)引用技術(shù)的模式下, __block id x,不會(huì)保留x。在ARC模式下, __block id x;默認(rèn)會(huì)保留x(就像其它值一樣)。為了在ARC下達(dá)到手動(dòng)引用技術(shù)的效果,你可以使用 __unsafe__unretained __block id x ;然而,就像 __unsafe_unretained名字蘊(yùn)含的那樣,擁有一個(gè)未保留變量(non-retained variable)是危險(xiǎn)的(因?yàn)樗赡苁且粋€(gè)野指針),因此***不要使用。有兩個(gè)更好的選擇是要么使用 __weak(如果你不需要支持IOS4或OS X v10.6),要門設(shè)置 __block值nil來打破循環(huán)引用。
以下的代碼片段說明了在手動(dòng)引用技術(shù)下時(shí)常會(huì)使用的模式。

  1. MyViewController *myController = [[MyViewController alloc] init…]; 
  2. // ... 
  3. myController.completionHandler =  ^(NSInteger result) { 
  4.    [myController dismissViewControllerAnimated:YES completion:nil]; 
  5. }; 
  6. [self presentViewController:myController animated:YES completion:^{ 
  7.    [myController release]; 
  8. }]; 

如上所屬,你可以使用 __block限定符來替代,并在 completion處理方法中將myController的值設(shè)置為nil:

  1. MyViewController * __block myController = [[MyViewController alloc] init…]; 
  2. // ... 
  3. myController.completionHandler =  ^(NSInteger result) { 
  4.     [myController dismissViewControllerAnimated:YES completion:nil]; 
  5.     myController = nil; 
  6. }; 

或者,你可以使用一個(gè)臨時(shí)的 __weak變量。以下代碼列舉了一個(gè)簡單的實(shí)現(xiàn):

  1. MyViewController *myController = [[MyViewController alloc] init…]; 
  2. // ... 
  3. MyViewController * __weak weakMyViewController = myController; 
  4. myController.completionHandler =  ^(NSInteger result) { 
  5.     [weakMyViewController dismissViewControllerAnimated:YES completion:nil]; 
  6. }; 

而對于特殊的循環(huán),你應(yīng)該使用:

  1. MyViewController *myController = [[MyViewController alloc] init…]; 
  2. // ... 
  3. MyViewController * __weak weakMyController = myController; 
  4. myController.completionHandler =  ^(NSInteger result) { 
  5.     MyViewController *strongMyController = weakMyController; 
  6.     if (strongMyController) { 
  7.         // ... 
  8.        [strongMyController dismissViewControllerAnimated:YES completion:nil]; 
  9.         // ... 
  10.     } 
  11.     else { 
  12.         // Probably nothing... 
  13.     } 
  14. }; 

某些情況下如果一個(gè)類不兼容__ weak,你可以使用 __unsafe_unretained。但這也不適用于特殊的循環(huán),因?yàn)樵趯?shí)際問題中驗(yàn)證 __unsafe_unretained指針是否仍有效或是否仍指向相同的對象,是非常困難或根本不可能實(shí)現(xiàn)的。
【ARC使用新聲明來管理自動(dòng)釋放池】(ARC Uses a New Statement to Manage Autorelease Pools)
使用ARC,你不能直接使用NSAutoreleasePool類來管理自動(dòng)釋放池。相反,你需要使用 @autoreleasepool塊:

  1. @autoreleasepool { 
  2.      // Code, such as a loop that creates a large number of temporary objects. 

這個(gè)簡單的結(jié)構(gòu)讓編譯器來判斷引用計(jì)數(shù)的狀態(tài)。在入口,自動(dòng)釋放池會(huì)被push。在正常退出( break,return,goto,fall-through,dengd)自動(dòng)釋放池會(huì)被pop。出于對已有代碼兼容性的考慮,如果因異常導(dǎo)致退出,自動(dòng)釋放池將不會(huì)被pop。
該語法在所有Objecti-C模式下都可用。相比使用 NSAutoreleasePool類來說, @autoreleasepool更加高效;因此鼓勵(lì)你在使用 NSAutoreleasePool的地方使用 @autoreleasepool。
【跨平臺(tái)下Outlets管理保持一致的模式】(Patterns for Managing Outlets Become Consistent Across Platforms)

ARC下的IOS和OS X中聲明outlets的模式已經(jīng)發(fā)生變化,并且在跨平臺(tái)下保持一致性。你通常應(yīng)該接受的是:outlets應(yīng)該是 weak的,除了那些在nib文件(或storyboard屏)中File‘s Owner指向的***對象應(yīng)該是 strong的。
Resource Programming Guide.中的 ”Nib Files“做出了全面的解釋。
【堆變量會(huì)初始化為nil】(Stack Variables Are Initialized with nil)
使用ARC,strong,weak,以及autoreleasing的堆變量現(xiàn)在會(huì)隱式的初始化為nil,例如:

  1. - (void)myMethod { 
  2.     NSString *name; 
  3.     NSLog(@"name: %@", name); 

輸出的 name的值為null而不可能是程序崩潰。
【使用編譯器指令來啟用或禁用ARC】(Use Compiler Flags to Enable and Disable ARC)
使用 -fobjc-arc編譯指令來啟動(dòng)ARC。如果在某些文件中使用手動(dòng)引用技術(shù)對你來說更方便些,你可以選擇在單獨(dú)的文件上使用ARC。對于默認(rèn)使用ARC的工程,你可以使用 fno-objc-arc編譯指令來禁用某個(gè)文件的ARC。
Xcode4.2及更高版本,OS X v10.6及更高版本(64為應(yīng)用),IOS4版本或更高版本支持ARC。OS X v10.6和IOS4不支持弱引用。Xcode4.1及早期版本的Xcode不支持ARC。
【管理Toll-Free橋接】(Managing Toll-Free Bridging)
在許多Cocoa應(yīng)用中,你可以使用Core Foundation樣式的對象,不管是來自于Core Foundation框架本身(例如, CFArrayRefCFMutableDictionaryRef),還是來自于諸如Core Graphics一樣采用Core Foundation約定的框架(你可能使用向 CGColorSpaceRef and CGGradientRef樣式的類型)。
編譯器不會(huì)自動(dòng)管理Core Foundation對象的生命周期;你必須調(diào)用符合Core Founda內(nèi)存管理規(guī)則的CFRetain和CFRelease方法(或者合適的特殊類型變體)來釋放對象。(參見 Memory Management Programming Guide for Core Foundation
如果你在Objective-C對象和Core Foundation樣式對象間執(zhí)行類型轉(zhuǎn)換,你要告訴編譯器對象的歸屬語義,不管對象是使用類型轉(zhuǎn)換(定義在objc/runtime.h)或Core Foundation樣式的宏(定義在NSObject.h)。
__bridge在Objective-C和Core Foundation間的指針轉(zhuǎn)換不附加對象的所有權(quán)。
__bridge_retained或 CFBridgingRetain將Objectiv-C指針轉(zhuǎn)換為Core Foundation指針,并且將對象的所有權(quán)轉(zhuǎn)給你。你負(fù)責(zé)調(diào)用CFRelease或相關(guān)的函數(shù)來放棄對象的所有權(quán)。
__bridge_transfer或 CFBridgingRelease將一個(gè)非Objective-C指針轉(zhuǎn)移到Objective-C指針,并將對象所有權(quán)轉(zhuǎn)交給ARC。ARC負(fù)責(zé)放棄對象的所有權(quán)。
例如,如果你有這樣的代碼:

  1. - (void)logFirstNameOfPerson:(ABRecordRef)person { 
  2.     NSString *name = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty); 
  3.     NSLog(@"Person's first name: %@", name); 
  4.     [name release]; 

你應(yīng)該替代為:

  1. - (void)logFirstNameOfPerson:(ABRecordRef)person { 
  2.    
  3.     NSString *name = (NSString *)CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty)); 
  4.     NSLog(@"Person's first name: %@", name); 

【編譯器處理Cocoa方法返回的CF對象】(The Compiler Handles CF Objects Returned From Cocoa Methods)
編譯器了解Objective-C的那些沿用Cocoa命名規(guī)則返回Core Foundation類型的方法(參見 Advanced Memory Management Programming Guide)。例如,編譯器知道,在IOS中, UIColorCGColor方法返回的CGColor不會(huì)被擁有。你仍需使用合適的類型轉(zhuǎn)換,如下例所示:

  1. NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]]; 
  2. [colors addObject:(id)[[UIColor lightGrayColor] CGColor]]; 

【使用所有權(quán)關(guān)鍵字對函數(shù)參數(shù)進(jìn)行強(qiáng)制類型轉(zhuǎn)換】(Cast Function Parameters Using Ownership Keywords)
函數(shù)調(diào)用中在Objective-C和Core Foundation對象之間進(jìn)行轉(zhuǎn)換,你要告訴編譯器被傳入的對象的所有權(quán)語義。Core Foundation的所有權(quán)規(guī)則在Core Foundation的內(nèi)存管理規(guī)則中都已近說明了(參見 Memory Management Programming Guide for Core Foundation);Objective-C對象的規(guī)則在 Advanced Memory Management Programming Guide.有說明。
在下面的代碼片段中,傳入 CGGradientCreateWithColors函數(shù)的數(shù)組需要一個(gè)合適的類型轉(zhuǎn)換。 arrayWithObjects:方法返回的對象的所有權(quán)不會(huì)傳給函數(shù),因此需要用 __bridge轉(zhuǎn)換。

  1. NSArray *colors = <#An array of colors#>; 
  2. CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations); 

以下方法實(shí)現(xiàn)中展示了代碼片段。要注意的是遵從Core Foundation內(nèi)存管理規(guī)則的Core Foundation內(nèi)存管理函數(shù)的用法。

  1. - (void)drawRect:(CGRect)rect { 
  2. 02      CGContextRef ctx = UIGraphicsGetCurrentContext(); 
  3. 03      CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); 
  4. 04      CGFloat locations[2] = {0.0, 1.0}; 
  5. 05      NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]]; 
  6. 06      [colors addObject:(id)[[UIColor lightGrayColor] CGColor]]; 
  7. 07      CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations); 
  8. CGColorSpaceRelease(colorSpace);  // Release owned Core Foundation object. 
  9. CGPoint startPoint = CGPointMake(0.0, 0.0); 
  10. CGPoint endPoint = CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMaxY(self.bounds)); 
  11. CGContextDrawLinearGradient(ctx, gradient, startPoint, endPoint, 
  12. kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); 
  13. CGGradientRelease(gradient);  // Release owned Core Foundation object. 

 

不要走開,下頁內(nèi)容更銷魂

#p#

【工程轉(zhuǎn)換時(shí)的常見問題】(Common Issues While Converting a Project)
當(dāng)遷移已有工程時(shí),可能你會(huì)遇到許多問題。這里列舉一些常見問題,以及解決辦法。
1.不能調(diào)用 retain, release,或 autorelease。
這是一個(gè)特殊點(diǎn)。你也不能寫:
while ([x retainCount]) { [x release]; }
2.不能調(diào)用 dealloc
如果你實(shí)現(xiàn)了一個(gè)單例對象或在init方法中替換一個(gè)對象,你通常會(huì)調(diào)用 dealloc方法。對于單例對象,使用共享實(shí)例模式。在 init方法中,你不再需要調(diào)用dealloc,因?yàn)閷ο笤谀阒貙? self時(shí)會(huì)被釋放掉。
3.不能使用 NSAutoreleasePool對象
使用新的 @autoreleasepool{}結(jié)構(gòu)代替。這在你的自動(dòng)釋放池中強(qiáng)制使用block結(jié)構(gòu),并且比 NSAutoreleasePool要快六倍。即使在非ARC的代碼中 @autoreleasepool也能工作,因?yàn)? @autoreleasepool較 NSAutoreleasePool要快得多,所以許多舊的”性能hacks“會(huì)無條件的被 @autoreleasepool所替代。
遷移器只處理 NSAutoreleasePool的簡單用法,不能處理復(fù)雜條件下的情況,或者一個(gè)定義在新的 @autoreleasepool結(jié)構(gòu)內(nèi)部的變量并在其之外使用的情況。
4.ACR需要你將在init方法中 [super init]的結(jié)果賦值給 self。
下面的代碼在ARC的init方法中是不合法的: 

  1. [super init]; 

簡單的修正是做如下變換 

  1. self = [super init]; 

更全面的改法是在繼續(xù)之前檢測結(jié)果是否為nil:

  1. self = [super init]; 
  2. if (self) { 
  3.    ... 

5.不能實(shí)現(xiàn)自定義的 retain和 release方法
實(shí)現(xiàn)自定義的 retain和 release方法會(huì)打破弱引用。有幾種常見原因是想要提供提供自定義實(shí)現(xiàn)的:
性能
請不要再這么做了; NSObject的 retain和 release現(xiàn)在更加快捷。如果你仍發(fā)現(xiàn)問題,請?zhí)峤籦ug。
實(shí)現(xiàn)自定義的弱指針系統(tǒng)
使用 __weak代替
實(shí)現(xiàn)單例類
使用共享示例代替?;蚴褂妙惙椒愄娲鷮?shí)例方法,這避免了一直都要去分配對象空間的操作。
6."Assigned"實(shí)例變量成為了strong類型
在ARC之前,實(shí)例變量是非擁有引用(non-owning redernces)——直接將對象賦值給實(shí)例變量不會(huì)擴(kuò)展對象的生命周期。為了令屬性成為強(qiáng)類型,你通常只要實(shí)現(xiàn)或合成訪問器方法,它們會(huì)調(diào)用合適的內(nèi) 存管理方法;相比較而言,你可能已經(jīng)如下例子中實(shí)現(xiàn)了訪問器方法來維護(hù)一個(gè)弱類型屬性。

  1.     @interface MyClass : Superclass { 
  2.     id thing; // Weak reference. 
  3. // ... 
  4. @end 
  5. @implementation MyClass 
  6. - (id)thing { 
  7.     return thing; 
  8. - (void)setThing:(id)newThing { 
  9.     thing = newThing; 
  10. // ... 
  11. @end 

使用ARC,實(shí)例變量默認(rèn)是強(qiáng)類型引用——將實(shí)例變量直接賦值給對象的確會(huì)擴(kuò)展對象的生命周期。遷移工具沒辦法決定實(shí)例變量何時(shí)應(yīng)該是 weak類型的。為了像之前那樣維護(hù)同樣的行為,你必須將實(shí)例變量標(biāo)記為 weak類型,或使用一個(gè)聲明式屬性。

  1. @interface MyClass : Superclass { 
  2.     id __weak thing; 
  3. // ... 
  4. @end 
  5. @implementation MyClass 
  6. - (id)thing { 
  7.     return thing; 
  8. - (void)setThing:(id)newThing { 
  9.     thing = newThing; 
  10. // ... 
  11. @end 
  12. 或 
  13. @interface MyClass : Superclass 
  14. @property (weak) id thing; 
  15. // ... 
  16. @end 
  17. @implementation MyClass 
  18. @synthesize thing; 
  19. // ... 
  20. @end 

7.在C語言結(jié)構(gòu)體重不能使用強(qiáng)類型的ids,例如,以下代碼會(huì)編譯不過

  1. struct X { id x; float y; }; 

因?yàn)閤默認(rèn)肯定是被保留的,編譯器無法安全的合成所有保證代碼正常運(yùn)轉(zhuǎn)所需的所有代碼。例如,如果你通過一些最終會(huì)被釋放的代碼來傳入一個(gè)指針到這些結(jié)構(gòu) 體后,每個(gè)id在結(jié)構(gòu)體回收之前會(huì)被被迫釋放掉。編譯器不能可靠的做到這點(diǎn),所以在結(jié)構(gòu)體中的強(qiáng)類型的ids在ARC模式下是完全無效的。以下有幾個(gè)可能 的解決辦法:
(1)使用Objective-C對象代替結(jié)構(gòu)體
這是***的實(shí)踐方法。
(2)如果使用Objective-C對象是次優(yōu)方案,(可能你想要這些結(jié)構(gòu)體組成的一個(gè)數(shù)組)那么考慮void *進(jìn)行替代。
這需要使用顯示的類型轉(zhuǎn)換,在下面會(huì)提到。
(3)將對象引用標(biāo)記為__unsafe_unretained
該方法對于一些不常見的模式可能會(huì)有效,如下:

  1. struct x { NSString *S;  int X; } StaticArray[] = { 
  2.        @"foo", 42, 
  3.        @"bar, 97, 
  4.          ... 
  5. }; 

這可能存在問題,并且如果對象在指針之外會(huì)被釋放掉,這是不安全的,但實(shí)際對于像字符串常量一樣一直存在的東西來說確實(shí)很有用的。
8.不能在 id與 void *(包括Core Foundation類型)之間進(jìn)行直接轉(zhuǎn)換
“Managing Toll-Free Bridging.”中由詳細(xì)的描述。
【常見問題】(Frequently Asked Questions)      
我該怎樣理解ARC?它把retians/releases放在哪里呢?
嘗試不要再考慮retain/release應(yīng)該放在哪,要考慮你應(yīng)用的邏輯??紤]你對象中的”strong和weak“指針,對象的所有權(quán),可能的循環(huán)引用。
我是否還需要為我的對象編寫dealloc方法?
可能需要。
因?yàn)锳RC不會(huì)自動(dòng)操作malloc/free,Core Foundation對象的生命周期管理,文件描述,等等。你仍需要在dealloc方法中是否這樣的資源。
你不需要(實(shí)際根本不需要)釋放實(shí)例變量,但是你需要在系統(tǒng)類和其它未使用ARC編譯的代碼上調(diào)用[self setDelegate:nil]。
ARC中的dealloc方法不需要或不允許調(diào)用[super dealloc];到super的鏈?zhǔn)浇Y(jié)構(gòu)是在運(yùn)行期進(jìn)行處理和實(shí)施的。
在ARC中仍存在循環(huán)引用嗎?
是的。
ARC自動(dòng)處理retain/release,并且繼承了循環(huán)引用的問題。幸運(yùn)的是,遷移到ARC的代碼很少內(nèi)存泄露,因?yàn)閷傩裕╬roperty)已經(jīng)聲明了是否要保留。
在ARC下我能創(chuàng)建C數(shù)組的保留指針不?
是的,可以!

  1. // Note calloc() to get zero-filled memory. 
  2. __strong SomeClass **dynamicArray = (__strong SomeClass **)calloc(sizeof(SomeClass *), entries); 
  3. for (int i = 0; i < entries; i++) { 
  4.      dynamicArray[i] = [[SomeClass alloc] init]; 
  5. // When you're done, set each entry to nil to tell ARC to release the object. 
  6. for (int i = 0; i < entries; i++) { 
  7.      dynamicArray[i] = nil; 
  8. free(dynamicArray); 

有些其它需要注意的地方:
某些情況下你需要使用__strong SomeClass **,因?yàn)槟J(rèn)是__autoreleasing SomeClass **.
分配的內(nèi)存必須是零填充的
你必須在釋放數(shù)組(memset或bzero無法工作)之前將每個(gè)元素設(shè)置為nil.
避免使用memcpy或realloc
ARC運(yùn)行速度會(huì)慢嗎?
這取決于你的測量方式,但基本”很快“。編譯器高效的消除許多外部的 retian和 release調(diào)用,而且總的來說會(huì)更加關(guān)注于提升Objective-C運(yùn)行時(shí)的速度。尤其是,當(dāng)調(diào)用者是ARC代碼時(shí),常用的"返回一個(gè) retain/autoreleased對象"模式會(huì)更快速而且實(shí)際上并沒有將對象放入到自動(dòng)釋放池中。
我可以在特定文件下退出ARC嗎?
可以。
在你遷移工程來使用ARC時(shí),-fobjc-arc編譯器標(biāo)記默認(rèn)會(huì)設(shè)置到每個(gè)Objective-C的源文件。你可以使用 -fno-objc-arc編譯器標(biāo)記來在特定的類中禁用ARC。在Xcode中,在target的 Build Phases中,打開 Compile Sources 組顯示源文件列表。雙擊你想要設(shè)置標(biāo)記的文件,在pop-up面板中輸入-fno-objc-arc指定,之后點(diǎn)擊完成。

Apple Doc

責(zé)任編輯:閆佳明 來源: oschina
相關(guān)推薦

2024-06-25 08:18:55

2017-07-20 16:55:56

Android事件響應(yīng)View源碼分析

2019-07-23 08:55:46

Base64編碼底層

2021-04-07 13:28:21

函數(shù)程序員異步

2024-05-17 10:05:06

Java機(jī)制應(yīng)用

2025-01-26 15:38:11

Spring事務(wù)編程式

2020-10-09 08:15:11

JsBridge

2015-07-15 17:09:48

HiveHadoop分布式文件系統(tǒng)

2017-09-05 08:52:37

Git程序員命令

2022-02-21 09:44:45

Git開源分布式

2023-05-12 08:19:12

Netty程序框架

2021-06-30 00:20:12

Hangfire.NET平臺(tái)

2019-04-17 15:16:00

Sparkshuffle算法

2021-04-09 08:40:51

網(wǎng)絡(luò)保險(xiǎn)網(wǎng)絡(luò)安全網(wǎng)絡(luò)風(fēng)險(xiǎn)

2025-03-07 08:24:10

Javavolatilecount++

2024-05-10 08:19:59

arthasjava字節(jié)碼

2023-07-30 15:18:54

JavaScript屬性

2023-05-08 08:21:15

JavaNIO編程

2021-01-26 23:46:32

JavaScript數(shù)據(jù)結(jié)構(gòu)前端

2021-03-09 14:04:01

JavaScriptCookie數(shù)據(jù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號