簡介
ARC是編譯器特性,而不是iOS運行時特性(除了weak指針系統)【ARC和手動內存管理性能是一樣的,有些時候還能更加快速,因爲編譯器還可以執行某些優化】
指針保持對象的生命
ARC的規則非常簡單:只要還有一個變量指向對象,對象就會保持在內存中。(當指針指向新值,或者指針不再存在時,相關聯的對象就會自動釋放)
我們可以按“所有權”(ownership)來考慮ARC對象,一個對象可以有多個擁有者。只有當對象一個擁有者也沒有的情況下才被釋放。而能夠作爲對象擁有者的指針爲“strong”,默認的實例變量和本地變量都是strong類型的指針。
另外還有一種“weak”指針,weak變量仍然指向一個對象,但不是對象的擁有者;當weak指向的變量的擁有者不再擁有時,變量被釋放,此時weak變量會自動變爲nil,稱爲“zeroing weak pointer”,這樣阻止了weak指針繼續指向已釋放的對象。
weak指針主要用於“父-子”關係,父親擁有一個兒子的strong指針,因此是兒子的所有者;但爲了阻止所有權迴環,兒子需要使用weak指針指向父親,典型例子是delegate模式
id obj = [array objectAtIndex:0]; [array removeObjectAtIndex:0]; NSLog(@"%@",obj);
在ARC中這段代碼是完全合法的。
ARC的限制
ARC只能工作與Objective-C對象,如果應用使用了Core Foundation 或malloc()/free(),此時需要你來管理內存。因爲strong指針會保持對象的生命,某些情況下你仍然需要手動設置這些指針爲nil,無論你何時創建了一個新對象時,都需要考慮誰擁有該對象,以及這個對象需要存活多久。
XCode 的ARC遷移
ARC是LLVM3.0編譯器的特性,而現有工程可能使用老的GCC4.2或LLVM-GCC編譯器,因此需要首先設置使用LLVM3.0編譯器
Project Settings -> target -> Build Settings 搜索compiler,同樣,Build Options 下面的Run Static Analyzer選項也最好啓用,這樣每次Xcode編譯項目時,都會運行靜態代碼分析工具來檢查我們的代碼(Xcode的ARC 自動轉換可上網搜索方法,在這裏不做闡述)
-fno-obj-arc 可以禁止某些文件的ARC
屬性 property
對於.h 頭文件,Xcode主要是將屬性定義由retain變爲strong,這些屬性是類對外的接口,因此定義在.h文件中
在ARC之前,開發者經常會在.m實現文件中使用class extension 來定義 private property,這樣做主要是簡化實例對象的手動內存管理,讓property的setter方法自動管理原來對象的釋放,以及新對象的retain,但是有了ARC,這樣的代碼就不再需要了,一般來說,僅僅爲了簡化內存管理,是不再需要使用property的,只有那些屬於public接口的實例變量,才應該定義爲property。
我們可以直接在.m類實現中定義private實例變量
NSMutableString *currentStringValue; NSMutableArray *searchResults; SoundEffect *soundEffect;
我們在使用時,雖然沒有定義property,也可以直接 [self.soundEffect play],也可以[[self soundEffect] play]
作爲property的最佳實踐,如果你定義了某個東西爲property,則你應該在任何地方都按屬性來使用它。
在ARC中,所有*outlet*屬性都推薦使用weak,這些view對象已經屬於View Controller 的view hierarchy ,不需要再次定義爲strong,唯一使用strong的outlet是File’s Owner,連接到nib的頂層對象
將outlet 定義爲weak的優點是簡化了viewDidUnload方法的實現。只要你保持一個對象的指針,對象就會存活,當你不需要某個對象時,可以手動設置指針爲nil。
property的修飾符總結:
strong:等同於“reatain”屬性稱爲對象的擁有者
weak:屬性是weak pointer ,當對象釋放時會自動設置爲nil,記住Outlet應該使用Weak
unsafe_unretained:等同於之前的“assign”只有iOS4才應該使用
copy:和之前的copy一樣,複製一個對象並創建strong關聯
assign:對象不能使用assign,但原始類型(BOOL,int,float)仍然可以使用
ReadOnly property
在ARC之前,我們可以如下定義一個readonly property:@property(nonatomic,readonly)NSString *result;這回隱式創建一個assign property,這種用法對於readonly值來說是適當的,畢竟你何必對只讀數據進行retain那,但在ARC中會報錯;你必須顯式使用strong,weak或unsafe_unretained,多數情況下使用strong是正確的
@property(nonatomic, strong, readonly) NSString *result;
對於readonly property,我們應該總是使用self.propertyName來訪問實例變量(除了init和自定義的getter和setter方法),否則直接修改實例變量會混淆ARC並導致奇怪的Bug,正確的方法是使用class extension 重新定義 property爲readwrite;
.h文件:@property (nonatomic, strong, readonly) NSNumber *temperature;
.m 文件:@property(nonatomic, strong, readwrite) NSNumber *temperature;