2012-09-27 51 views
0

如果我們繼承UIView,在任何的這個新類的實例方法,做在iOS上,在UIView的實例方法中,如果我們做[self removeFromSuperview],爲什麼自我繼續存在?

[self removeFromSuperview]; 

[foo someMessage]; 
_a = _a + 1; 
self.b++; 
for (int i = 0; i < 100000000; i++) { 
    self.b++; 
    //NSLog(@"b is %i", self.b); 
} 

會發生什麼?假設超級視圖是唯一聲稱擁有此視圖的所有者,那麼將立即釋放self

第一行是發送一個局部變量foo引用外部對象的消息someMessage。第二行是一個局部變量_b。第三行是屬性b。接下來的幾行只是延遲一些。

嘗試使用Xcode 4.5和iPhone 5(iOS 6)時,代碼實際上運行時不會崩潰。代碼在-touchesBegan內完成。只有在大延遲循環完成後,視圖纔會在屏幕上消失,可能是因爲主循環現在調用drawRect代替rootViewController.view,並且顯示視圖已經消失(視圖在延遲循環之前從視圖層次中消失了,但沒有反映在屏幕上)。

如果我只將循環計數到1000或10000,並在該循環內使用NSLog,則該數字實際上可以很好地打印出來而不會發生任何崩潰。 更新:據說該對象可能仍然可以訪問一段時間,但似乎即使是30秒或一分鐘,代碼仍然運行沒有任何問題。

那麼這是如何工作的?如果使用儀器,我實際上只能看到這個FooView對象在大延遲循環後才離開「分配」表。所以奇怪的是,似乎FooView對象直到後來才被釋放,而不是在removeFromSuperView的位置。

我也有一個[self.presentingViewController dismissViewControllerAnimated ...]即駁回self,然後下一行,self.presentingViewController再次使用,self.presentingViewController成爲nil,但如果我還添加了一個循環遞增整數屬性爲10000和使用NSLog打印出來,它打印出來也很好。

回答

1

假設超級視圖是唯一一個聲稱擁有這個視圖的所有權,將自動被釋放嗎?

是的,可能,但內存實際上並沒有得到重用或清除;你可以經常仍然得到什麼似乎是一個有效的對象,如果在釋放後沒有其他事情發生。

嘗試:

[self removeFromSuperview]; 
[self performSelector:@selector(tryToCrash) withObject:nil afterDelay:0.1]; 

//... 

- (void)tryToCrash 
{ 
    [foo someMessage]; 
    _a = _a + 1; 
    self.b++; 
    for (int i = 0; i < 100000000; i++) { 
     self.b++; 
     //NSLog(@"i is %i", self.i); 
    } 
} 

將安排運行循環的下一次復飛後出現的代碼,你可能會看到一個崩潰。最主要的是你正在使用一個你知道已經死了的對象,這個對象不是C的UB級別,但肯定不能保證給你任何特定的結果。

只有大延遲循環結束後的視圖將消失在屏幕上,這可能是由於主循環現在呼籲的drawRect

右鍵,視圖只重畫一次,每次通過運行循環,只有當他們被標記爲需要它時。由於其子視圖中的一個子視圖已被刪除,所以超級視圖將如此標記。它也有可能延遲實際釋放子視圖直到這一點。

+0

如果你有一個懸掛指針,訪問它仍然會崩潰,即使內存還沒有被重用。 –

+0

@Carl:_發送message_不會。 'NSNumber * n = [[NSNumber alloc] initWithInteger:10]; [n版本]; NSLog(@「%f」,[n floatValue]);' –

+1

哇。 「NSNumber」就是一個很好的例子,因爲它有各種優化,但是一個簡單的NSObject子類仍然會在釋放後立即對消息作出響應,並且至少在改變堆的其他操作之前不會崩潰,但是不會100%機會。現在我想到它確實很有意義。感謝您的啓發! –

相關問題