天天看點

Automatic Reference Counting (ARC) 自動引用計數

http://developer.apple.com/library/mac/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html    

         Automatic Reference Counting (ARC)是一個編譯器的功能,提供了對Objective-C對象的自動記憶體管理。ARC在編譯期間自動在适當的地方添加Objective-C對象的retain和release操作代碼。

Automatic Reference Counting (ARC) 自動引用計數

一. 總結

    ARC在編譯期間,根據Objective-C對象的存活周期,在适當的位置添加retain和release代碼。從概念上講,ARC與手動引用計數記憶體管理遵循同樣的記憶體管理規則。ARC也無法防止strong引用循環。

    ARC還引入了新的修飾符來修飾變量和聲明屬性。變量的修飾符__strong,__weak, __unsafe_unretained,__autoreleasing,預設是_strong;聲明屬性的修飾符strong, weak, unsafe_unretained,預設是strong。

    Objective-C對象和Core Foundation-style對象直接的轉換。你需要顯示地告訴編譯器轉換後對象的所有權,轉換修飾符号:__bridge,

__bridge_retained

 或 

CFBridgingRetain,

__bridge_transfer

 或 

CFBridgingRelease

ARC支援的系統:Xcode4.2 forOS X v10.6和v10.7(64位應用程式)、iOS 4、iOS 5。weak不支援OS X v10.6和iOS 4。

    Xcode提供一個把手動引用計數轉換成ARC的工具,choose Edit > Refactor > Convert to Objective-C ARC。

二.ARC概述

      你不需記住什麼時候要用 retain, release, and autorelease,ARC評估你的對象的生命周期,并在編譯時自動插入适當的記憶體管理。編譯器還為你生成相應的dealloc方法。

       一個Person類聲明如下:

@interface Person : NSObject      
@property NSString *firstName;      
@property NSString *lastName;      
@property NSNumber *yearOfBirth;      
@property Person *spouse;      
@end      
@implementation Person      
@end      

        屬性的預設修飾符是strong。

       一個contrived方法如下:

- (void)contrived {      
Person *aPerson = [[Person alloc] init];      
[aPerson setFirstName:@"William"];      
[aPerson setLastName:@"Dudney"];      
[aPerson setYearOfBirth:[[NSNumber alloc] initWithInteger:2011]];      
NSLog(@"aPerson: %@", aPerson);      
}      

       ARC負責aPerson和NSNumber對象的記憶體釋放。

三.ARC強制執行新規則

      1.不能顯示調用 dealloc([super dealloc]), 執行或調用 retain, release, retainCount, or autorelease;禁止使用選擇器 @selector(retain), @selector(release), 等。

         你可以實作一個dealloc方法,來釋放執行個體變量以外的資源,例如:系統類調用[systemClassInstance setDelegate:nil]和未使用ARC編譯的代碼。在dealloc方法中,ARC在适當的地方添加release來負責釋放執行個體變量。

       2.不能使用 

NSAllocateObject

 和 

NSDeallocateObject類。

       3.不能在C結構體中使用對象指針。使用Objective-C類代替C結構體。

       4. id和void*之間要求顯示轉換。

          使用__bridge,__bridge_retained 或 CFBridgingRetain,__bridge_transfer 或 CFBridgingRelease來顯示轉換。

       5.用 

@autoreleasepool{}代替NSAutoReleasePool。

       6.不能使用memory zones。不再需要NSZone。

       7.執行個體變量的通路名稱不能用new作為字首,不能聲明一個屬性用new作為字首。

@property NSString *newTitle;//錯誤      
@property (getter=theNewTitle) NSString *newTitle;//修改通路方法,正确      

四.ARC 推出新的對象生命周期修飾符

   1.屬性聲明修飾符:strong, weak, unsafe_unretained,預設strong

     strong和retain相似,隻要有一個strong指針指向對象,該對象就不會被銷毀;(一個對象,要是沒有任何一個strong引用指向該對象,将馬上被銷毀);

     weak,聲明為weak的指針,weak指針指向的對象一旦被釋放,weak的指針都将被指派為nil;

      unsafe_unretained,用unsafe_unretained聲明的指針,指針指向的對象一旦被釋放,這些指針将成為野指針。

//以下2行代碼執行效果一樣      
@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;      
//聲明unsafe_unretained屬性      
@property (nonatomic, strong) NSString *string1;         
@property (nonatomic, unsafe_unretained) NSString *string2;      
//執行如下代碼後,self.string2成了野指針      
self.string1 = [[NSString alloc] initWithUTF8String:"string 1"];         
self.string2 = self.string1;         
self.string1 = nil;        
NSLog(@"String 2 = %@", self.string2);        

      為了避免strong(強引用)循環,parent對象strong(強引用)child對象,child對象weak(弱引用)parent對象。

    2.變量的修飾符__strong,__weak,__unsafe_unretained,__autoreleasing,預設是_strong

       __strong:強引用,隻要有一個strong引用指向該對象,那麼該對象就不會被銷毀;

       __weak:弱引用,不能保持一個對象的存活期,當弱引用指向的對象沒有強引用指向時,該弱引用指針被置為nil;

       __unsafe_unretained,跟__weak相似,隻是該引用指針成為野指針。

       __autoreleasing,修飾傳遞給方法的參數引用(id*),方法傳回時自動釋放。

       a) 變量定義格式如下:

ClassName * qualifier variableName;      
MyClass * __strong myStrongReference;//__strong是預設修飾符,等價于MyClass *myStrongReference;      
MyClass * __weak myWeakReference;      
MyClass * __unsafe_unretained myUnsafeReference;      
//string用NSString對象引用初始化後,由于沒有strong引用指向該NSString對象,NSString對象馬上就被釋放,string被置為nil;      
NSString * __weak string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]];      
NSLog(@"string: %@", string);//輸出null      

       b)__autoreleasing,方法的參數是個引用指針(id*):

         參數是個__autoreleasing的方法聲明如下:

- (BOOL)performOperationWithError:(NSError * __autoreleasing *)error;      
NSError *error;   //或定義成 NSError * _autoreleasing error;      
BOOL OK = [myObject performOperationWithError:&error];      
if (!OK) {      
// Report the error.      
// ...      

//編譯器自動添加了臨時__autoreleasing變量

NSError * __strong error;      
NSError * __autoreleasing tmp = error;      
BOOL OK = [myObject performOperationWithError:&tmp];      
error = tmp;      
if (!OK) {      
// Report the error.      
// ...      

//傳回_autoreleasing定義的變量

-(NSString*)name

{

       _autoreleasing NSString *str = [[NSString alloc] initWithString: @"name"];

       return name;

}

五. ARC編譯模式下,iOS和Mac OS X平台對Outlets(使用者接口變量) 的管理統一了

     strong: Nib檔案所有者(File's Owner)的頂層對象(top-level objects);

     weak:  視圖或其他視窗中的Outlets(使用者接口變量);

六. ARC編譯模式下,堆棧變量初始化為nil。

七. 使用編譯器标志啟用和禁用ARC

              -fobjc-arc        啟用ARC

       -fno-objc-arc     禁用ARC 

    a) ARC編譯選項

       項目檔案的[Build Settings]->[Apple LLVM compiler4.1 -Language]

Automatic Reference Counting (ARC) 自動引用計數

    b) 在ARC編譯模式下,某些源檔案禁用ARC

Automatic Reference Counting (ARC) 自動引用計數

八. Core fundation style 對象與Objective-C對象的橋接轉換(Toll-Free bridge)

     ARC不自動負責Core Foundation-style 對象(例如

CFArrayRef

CFMutableDictionaryRef、

CGColorSpaceRef

、 

CGGradientRef

)的記憶體釋放,你必須使用

CFRetain

 and 

CFRelease管理

Core Foundation-style對象。

      Objective-C對象和Core Foundation-style對象的轉換,你需要顯式告訴編譯器轉換後的對象的所有權。

     a) __bridge,隻做類型轉換,但是不修改對象(記憶體)管理權;

     b) 

__bridge_retained或

CFBridgingRetain,将Objective-C的對象轉換為Core Foundation的對象,同時将對象(記憶體)的管理權交給我們,後續需要使用CFRelease或者相關方法來釋放對象;

     c) 

__bridge_transfer

CFBridgingRelease

,将Core Foundation的對象轉換為Objective-C的對象,同時将對象(記憶體)的管理權交給ARC。

九. 手動轉換項目支援ARC

     a) 不能調用

retain

release

,  

autorelease

.方法;

      b)  不能調用dealloc方法;例如:[super dealloc];

      c)  用@autorelesepool{}代替NSAutoreleasePool;

      d)  init初始化方法, 

[super init]

 改成 

self = [super

init];

[super init];//錯誤      
self = [super init];//正确      
if (self) {      
...      

     e)  沒有使用ARC,類的執行個體變量預設是assign,對象指派給執行個體變量,不會改變對象的引用計數;

            使用ARC後,類的執行個體變量預設是strong,對象指派給執行個體變量,會延長對象的存活周期。

     f) 不能在C結構體中使用strong id;

struct X { id x; float y; };//錯誤      

     g)  id和void*(including Core Foundation types)之間不能直接互相轉換;

     h)  Nib中的非頂層對象Outlets(使用者接口變量),修飾符assign改為weak;

          頂層對象Outlets,修飾符retain改為strong。

十. 其他

a)__weak

不支援這些類的對象

:

     NSATSTypesetter

NSColorSpace

NSFont

NSMenuView

NSParagraphStyle

NSSimpleHorizontalTypesetter

, and 

NSTextView

b) ARC不支援管理的内容: 

malloc

/

free配置設定的對象

, Core Foundation-style 對象, file descriptors。

Core Foundation-style 對象,它是由C的struct定義的各種對象,主要來自于CoreFoundation架構(如CFArray或者CFMutableDictionaryRef類型),或者其它采用CoreFoundation命名規範的架構,如Core Graphics(如,CGColorSpaceRef 和CGGradientRef)。

繼續閱讀