iPhone開發之深刻淺出 (1) — ARC是什麼

ARC是什麼 函數

ARC是iOS 5推出的新功能,全稱叫 ARC(Automatic Reference Counting)。簡單地說,就是代碼中自動加入了retain/release,原先須要手動添加的用來處理內存管理的引用計數的代碼能夠自動地由編譯器完成了。 工具

該機能在 iOS 5/ Mac OS X 10.7 開始導入,利用 Xcode4.2 可使用該機能。簡單地理解ARC,就是經過指定的語法,讓編譯器(LLVM 3.0)在編譯代碼時,自動生成實例的引用計數管理部分代碼。有一點,ARC並非GC,它只是一種代碼靜態分析(Static Analyzer)工具。 學習

變化點

經過一小段代碼,咱們看看使用ARC先後的變化點。 spa

@interface NonARCObject : NSObject {
    NSString *name;
}
-(id)initWithName:(NSString *)name;
@end

@implementation NonARCObject
-(id)initWithName:(NSString *)newName {
    self = [super init];
    if (self) {
        name = [newName retain];
    }
    return self;
}

-(void)dealloc {
    [name release];
    [Super dealloc];
}
@end
@interface ARCObject : NSObject {
    NSString *name;
}
-(id)initWithName:(NSString *)name;
@end

@implementation ARCObject
-(id)initWithName:(NSString *)newName {
    self = [super init];
    if (self) {
        name = newName;
    }
    return self;
}
@end
咱們以前使用Objective-C中內存管理規則時,每每採用下面的準則
  • 生成對象時,使用autorelease
  • 對象代入時,先autorelease後再retain
  • 對象在函數中返回時,使用return [[object retain] autorelease];

而使用ARC後,咱們能夠不須要這樣作了,甚至連最基礎的release都不須要了。 指針

使用ARC的好處

使用ARC有什麼好處呢? code

  • 看到上面的例子,你們就知道了,之後寫Objective-C的代碼變得簡單多了,由於咱們不須要擔憂煩人的內存管理,擔憂內存泄露了
  • 代碼的總量變少了,看上去清爽了很多,也節省了勞動力
  • 代碼高速化,因爲使用編譯器管理引用計數,減小了低效代碼的可能性

很差的地方

  • 記住一堆新的ARC規則 — 關鍵字及特性等須要必定的學習週期
  • 一些舊的代碼,第三方代碼使用的時候比較麻煩;修改代碼須要工數,要麼修改編譯開關

關於第二點,因爲 XCode4.2 中缺省ARC就是 ON 的狀態,因此編譯舊代碼的時候每每有」Automatic Reference Counting Issue」的錯誤信息。 orm

這個時候,能夠將項目編譯設置中的「Objectice-C Auto Reference Counteting」設爲NO。以下所示。 對象

若是隻想對某個.m文件不適應ARC,能夠只針對該類文件加上 -fno-objc-arc 編譯FLAGS,以下圖。 生命週期

ARC基本規則

  • retain, release, autorelease, dealloc由編譯器自動插入,不能在代碼中調用
  • dealloc雖然能夠被重載,可是不能調用[super dealloc]

因爲ARC並非GC,並須要一些規則讓編譯器支持代碼插入,因此必須清楚清楚了這些規則後,才能寫出健壯的代碼。 內存

Objective-C對象

ObjectiveC中的對象,有強參照(Strong reference)和弱參照(Weak reference)之分,當須要保持其餘對象的時候,須要retain以確保對象引用計數加1。對象的持有者(owner)只要存在,那麼該對象的強參照就一直存在。

對象處理的基本規則是
  • 只要對象的持有者存在(對象被強參照),那麼就可使用該對象
  • 對象失去了持有者後,即被破棄
強參照 (Strong reference)
(s1)

firstName做爲」natsu」字符串對象的最初持有者,是該NSString類型對象的Strong reference。

(s2)

這裏將firstName代入到aName中,即aName也成爲了@」natsu」字符串對象的持有者,對於該對象,aName也是Strong reference。

(s3)

這裏,改變firstName的內容。生成新的字符串對象」maki」。這時候firstName成爲」maki」的持有者,而@」natsu」的持有者只有aName。每一個字符串對象都有各自的持有者,因此它們都在內存中都存在。

(s4)

追加新的變量otherName, 它將成爲@」maki」對象的另外一個持有者。即NSString類型對象的Strong reference。

(s5)

將otherName代入到aName,這時,aName將成爲@」maki」字符串對象的持有者。而對象@」natsu」已經沒有持有者了,該對象將被破棄。

弱參照 (Weak reference)

接下來咱們來看看弱參照 (Weak reference) 的使用方式。

(w1)

與強參照方式一樣,firstName做爲字符串對象@」natsu」的持有者存在。便是該NSString類型對象的Strong reference。

(w2)

使用關鍵字__weak,聲明弱參照weakName變量,將firstName代入。這時weakName雖然參照@」natsu」,但還是Weak reference。即weakName雖然能看到@」natsu」,但不是其持有者。

(w3)

firstName指向了新的對象@」maki」,成爲其持有者,而對象@」natsu」由於沒有了持有者,即被破棄。同時weakName變量將被自動代入nil。

引用關鍵字

ARC中關於對象的引用參照,主要有下面幾關鍵字。使用strong, weak, autoreleasing限定的變量會被隱式初始化爲nil。

__strong

變量聲明缺省都帶有__strong關鍵字,若是變量什麼關鍵字都不寫,那麼缺省就是強參照。

__weak

上面已經看到了,這是弱參照的關鍵字。該概念是新特性,從 iOS 5/ Mac OS X 10.7 開始導入。因爲該類型不影響對象的生命週期,因此若是對象以前就沒有持有者,那麼會出現剛建立就被破棄的問題,好比下面的代碼。

NSString __weak *string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]];
NSLog(@"string: %@", string); //此時 string爲空

若是編譯設定OS版本 Deployment Target 設定爲這比這低的版本,那麼編譯時將報錯(The current deployment target does not support automated __weak references),這個時候,咱們可使用下面的__unsafe_unretained。

弱參照還有一個特徵,即當參數對象失去全部者以後,變量會被自動付上nil (Zeroing)。

__unsafe_unretained

該關鍵字與__weak同樣,也是弱參照,與__weak的區別只是是否執行nil賦值(Zeroing)。可是這樣,須要注意變量所指的對象已經被破棄了,地址還還存在,但內存中對象已經沒有了。若是仍是訪問該對象,將引發「BAD_ACCESS」錯誤。

__autoreleasing

該關鍵字使對像延遲釋放。好比你想傳一個未初始化的對像引用到一個方法當中,在此方法中實例化此對像,那麼這種狀況可使用__autoreleasing。他被常常用於函數有值參數返回時的處理,好比下面的例子。

- (void) generateErrorInVariable:(__autoreleasing NSError **)paramError {
    ....
    *paramError = [[NSError alloc] initWithDomain:@"MyApp" code:1 userInfo:errorDictionary];
}

....
{
    NSError *error = nil;
    [self generateErrorInVariable:&error];
    NSLog(@"Error = %@", error);
}

又如函數的返回值是在函數中申請的,那麼但願釋放是在調用端時,每每有下面的代碼。

-(NSString *)stringTest
{
    NSString *retStr = [NSString stringWithString:@"test"];

    return [[retStr retain] autorelease];
}

// 使用ARC

-(NSString *)stringTest
{
    __autoreleasing NSString *retStr = [NSString alloc] initWithString:@"test"];

    return retStr;
}

即當方法的參數是id*,且但願方法返回時對象被autoreleased,那麼使用該關鍵字。

總結

今天,咱們看到了基本的ARC使用規則
  • 代碼中不能使用retain, release, retain, autorelease
  • 不重載dealloc(若是是釋放對象內存之外的處理,是能夠重載該函數的,可是不能調用[super dealloc])
  • 不能使用NSAllocateObject, NSDeallocateObject
  • 不能在C結構體中使用對象指針
  • id與void *間的若是cast時須要用特定的方法(__bridge關鍵字)
  • 不能使用NSAutoReleasePool、而須要@autoreleasepool塊
  • 不能使用「new」開始的屬性名稱 (若是使用會有下面的編譯錯誤」Property’s synthesized getter follows Cocoa naming convention for returning ‘owned’ objects」)

從此,咱們將更加深刻ARC,學習其更多的特性。

相關文章
相關標籤/搜索