OC release之後 retainCount爲何爲1

在XCode中加入如下代碼:
 UILabel *label=[UILabel alloc];
[label setText:@"TestLabel"];
NSLog(@"%d",[label retainCount]);
[label release];
NSLog(@"%d",[label retainCount]);
理論上說,第一句話alloc了一個label,其保留計數器值爲1,第二句話對保留計數器的值不產生影響,第4句話release了label,其保留計數器的值應該變爲0,從而調用dealloc方法銷燬label,但事實上,NSLog輸出的結果爲:
 1
 1 
兩個NSLog結果都是1,更爲奇怪的是,如果在第二個NSLog之前加上一句NSLog,內容任意,如下:
UILabel *label=[UILabel alloc];
[label setText:@"TestLabel"];
NSLog(@"%d",[label retainCount]);
[label release];
NSLog(@"Anything Else");
NSLog(@"%d",[label retainCount]);
 
此時,原來的第二個NSLog會出現EXEC_BAD_ACCESS錯誤,如下:
self.window.rootViewController * self.viewController;   EXC_BAD_ACCESS 錯誤
NSLog輸出結果爲:
1
Anything Else
...錯誤代碼.....
 
這裏雖然出現了錯誤,但這樣的結果反而是正確的,因爲在NSLog之前,label已經被dealloc,這時發送給label的消息應該都不能被響應,會出現EXEC_BAD_ACCESS錯誤;但是,爲什麼之前第一種代碼寫法不是這樣的情況呢?
根據網上查閱的資料,也許可以得出以下結論,事實上label的確已經被dealloc了,保留計數器的值也已經變成0了,其原來佔用的內存也已經不可用 了,但是原來這塊內存中的內容還沒有變(標記刪除),將會在未來某個不確定的時間上被清理 ,這就是爲什麼NSLog輸出的label保留計數器的值仍爲1,而如果在此 之前再加上一個NSLog,則改變了原來這塊內存的內容,於是發送給label的消息不再會被響應,於是程序crash。
值得一提的是,並不是加了一句NSLog之後就一定會造成程序crash的,如果那句新加的NSLog沒有佔用原來label的內存,那下一句NSLog依舊能夠響應發送給label的消息,結果會類似第一種代碼所產生的結果,具體如下:
1
Anything Else
1
 
所以說,兩種情況都是有可能發生的,至於到底發生哪種情況,完全取決於合適系統清理掉label佔用的內存,也可以說取決於“運氣”,因爲這個時間是不確定的。由於蘋果源碼非開源,所以究竟是什麼樣的都知識猜測,以上內容皆網上結果,本人認爲retaincount最後爲1.永遠不可能爲0.具體論證如下:
老師模擬了release內部實現大致算法:
release()
{
if(retainCount>1)
retainCount--;
else
{dealloc();}
}
 
於是可以看出retainCount最終爲1的時候執行了dealloc();dealloc在類中實現了重寫,所以retainCount=1的時候進行了release()會自然的想到retainCount=0,這是多數人的自然思維.其實retainCount=1的時候進行release()就會執行dealloc(),外部實現了重寫dealloc()方法,所以這就是爲什麼程序retainCount=1的時候再次release()就會銷燬程序然後系統自然調用dealloc()的原因.
比如:

Student *stu=[Studentnew];//retainCount=1

[stu retain];  //retainCount=2;

[stu release];//執行如 release(){if(retainCount>1)retainCount--;else{dealloc();}}的操作   retainCount=1

[stu release];//執行如 release()內部的else中的操作 調用dealloc()方法,外部實現了重寫,故:調用dealloc();  此時retainCount=1 .

如果不加殭屍模式可以測試出來,在dealloc()函數中NSLog();一下,可以輸出兩次結果.

爲什麼可以輸出兩次結果而不是三次四次?請看如下dealloc實現代碼:

-(void)dealloc

{    NSLog(@"------->AA");

    [super dealloc];//調用了父類的dealloc();

}

以上重寫的dealloc()函數內部進行了父類的dealloc()方法調用,第一次retainCount=1的時候進行release(),會正常執行dealloc()並打印結果,此時進行了 [super dealloc];父類被銷燬,清空內存中內容,標記刪除.當再次執行release()的時候,retainCount=1不變,進行else中內容的操作,執行dealloc(),dealloc()函數內容還是先NSLog();輸出的時候沒有問題,當執行到 [super dealloc];的時候才出問題,說明程序crash掉是因爲父類被dealloc()的緣故,但是retainCount的值仍然是1.根據super()的dealloc情況而確定是否crash程序,海闊天空,真相大白了吧!!!大笑三聲哈哈哈.......

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章