iOS 學習日誌(4)----ARC rules

ARC工做原理xcode

每次建立一個類的實例,ARC就會分配一個內存塊,用來存儲這個實例的相關信息。這個內存塊保存着實例的類型,以及這個實例相關的屬性的值。安全

當實例再也不被使用時,ARC釋放這個實例使用的內存,使這塊內存可做它用。這保證了類實例再也不被使用時,它們不會佔用內存空間。app

可是,若是ARC釋放了仍在使用的實例,那麼你就不能再訪問這個實例的屬性或者調用它的方法。若是你仍然試圖訪問這個實例,應用極有可能會崩潰。this

ARC的一個基本規則:只要某個對象被任一strong指針指向,那麼它將不會被銷燬。若是對象沒有被任何strong指針指向,那麼就將被銷燬atom

一、strong關鍵字:與retain相似,引用計數自動+1。強引用,只要強持有某個實例,而且這個實例的強引用存在,就不能銷燬這個實例。默認下是強引用spa

下面的例子對 strong的使用,有很詳細的說明:指針

id __strong obj0 = [[NSObject alloc] init]; /* object A */
/** obj0 has a strong reference to object A
*/
id __strong obj1 = [[NSObject alloc] init]; /* object B */
/** obj1 has a strong reference to object B
*/
id __strong obj2 = nil;
/** obj2 has no reference
*/
obj0 = obj1;
/**Obj0 has a strong reference to object B, which has been assigned from obj1.
* So, obj0 does not have a strong reference to object A anymore.
* Object A is disposed of because no one has ownership of it.** At this moment, both obj0 and obj1 have strong references to object B.
*/
obj2 = obj0;
/** Through obj0, obj2 has a strong reference to object B.** At this moment, obj0, obj1 and obj2 have strong references to object B.
*/
obj1 = nil;
/** Because nil is assigned to obj1, strong references to object B disappear.
** At this moment, obj0 and obj2 have strong references to object B.*/
obj0 = nil;
/** Because nil is assigned to obj0, a strong reference to object B disappears.
** At this moment, obj2 has a strong reference to object B.*/
obj2 = nil;
/** Because nil is assigned to obj2, a strong reference to object B disappears.
* Object B is disposed of because no one has ownership of it*/

  1. id obj = [array objectAtIndex:0]; 
    [array removeObjectAtIndex:0]; 
    NSLog(@"%@",obj);

在MRC時代這幾行代碼應該就掛掉了,由於array中0號對象被remove之後就被當即銷燬了,所以obj指向了一個dealloced的對象,所以在NSLog的時候將出現EXC_BAD_ACCESS。而在ARC中因爲obj是strong的,所以它持有了array中的首個對象,array再也不是該對象的惟一持有者。即便咱們從array中將obj移除了,它也依然被別的指針持有,所以不會被銷燬。調試

二、weak關鍵字:與assign相似,但更聰明。弱引用類型的指針也能夠指向對象,可是並不會持有該對象。對象一旦被釋放,這些指向這個對象的weak指針都將被賦值爲nil。這樣的好處能有效的防止野指針。例如:code

  1. __weak NSString *str = [[NSString alloc] initWithFormat:…]; 
    NSLog(@"%@",str); //輸出是"(null)"

這兩句代碼沒有任何意義。因爲str是弱引用,不會持有alloc出來的對象。根據ARC的規則,一個對象沒有強引用,這個對象就會被釋放。orm

三、unsafe_unretained:顧名思義,不安全;與weak有點相似。指針也是能夠指向對象,可是並不會持有該對象。對象一旦被釋放,這些指向這個對象的unsafe_unretained指針並不會知道對象已被釋放,形成了野指針的出現,程序會crash。儘可能少用unsafe_unretained關鍵字,使用了必須手動去管理實例。例如:下面的代碼會崩潰

@property (nonatomic, strong) NSString *string1;  
@property (nonatomic, unsafe_unretained) NSString *string2; 

self.string1 = [[NSString alloc] initWithUTF8String:"string 1"];     
self.string2 = self.string1;     
self.string1 = nil;    
NSLog(@"String 2 = %@", self.string2);

四、__autoreleasing:可使對像延遲釋放。好比你想傳一個未初始化地對像引用到一個方法當中,在此方法中實始化此對像,那麼這種狀況將是__autoreleasing表演的時候

注:弱引用只能聲明爲變量類型,由於運行時它的值可能改變。弱引用絕對不能聲明爲常量

五、循環引用:一個類的實例一直都有強引用以至實例沒法釋放;(1)在兩個類實例彼此保持對方的強引用,使得每一個實例都使對方保持有效時會發生這種狀況。咱們稱之爲循環引用。

id test0 = [[Test alloc] init];
id test1 = [[Test alloc] init];
[test0 setObject:test1];
[test1 setObject:test0];


(2)類的實例本身引用本身的實例。

id test = [[Test alloc] init];
[test setObject:test];

附錄:

EXC_BAD_ACCESS:這種狀況是對指針對象的過分釋放,致使次指針爲野指針報錯。這類的報錯有時候是很難找出報錯的位置的。從網上資料找出2種調試方法:

<1>經過NSZombieEnabled (這方法常用,但少數的仍是沒法查找出來)

在xcode中Run,Stop 右邊也就是選擇設備的地方左邊找到 

 Scheme >Edit Scheme>Arguments>Environment Variables下添加

NSZombieEnabled               YES    

MallocStackLoggingNoCompact  YES

 MallocStackLogging                      YES

<2>經過重寫object的respondsToSelector方法,顯示出EXC_BAD_ACCESS前訪問的最後一個對象

你須要在每一個object的.m或者.mm文件中加入上面代碼,而且在 other c flags中加入-D _FOR_DEBUG_(記住請只在Debug Configuration下加入此標記)。這樣當你程序崩潰時,Xcode的console上就會準確地記錄了最後運行的object的方法。

 #ifdef _FOR_DEBUG_  
-(BOOL) respondsToSelector:(SEL)aSelector {  
    printf("SELECTOR: %s\n", [NSStringFromSelector(aSelector) UTF8String]);  
    return [super respondsToSelector:aSelector];  
}  
#endif
相關文章
相關標籤/搜索