2009-01-29 129 views
5

背景iPhone發展 - 模擬內存警告

我有一個標籤欄的應用程序。每個選項卡都包含導航控制器,允許用戶從一個視圖切換到另一個視圖,以顯示數據的深入信息(每個視圖由視圖控制器處理,每個視圖控制器類具有didReceiveMemoryWarning方法)。通過從Web服務提取數據來填充列表。

問題

當我使用「硬件>模擬內存警告」 iPhone模擬器的選項,該didReceiveMemoryWarning方法被稱爲我的所有視圖控制器 - 即使該用戶正在觀看一個。我不想清除活動視圖控制器正在使用的任何內容。我怎樣才能做到這一點?

哪些方法應該有實現來重新加載數據後,數據被釋放,因爲內存警告? (我看到了含有表視圖調用viewDidLoad方法,當用戶回來這種看法,但如果視圖包含(說UIWebView的),那麼viewDidLoad方法不叫視圖控制器類。這是爲什麼?)

編輯(星期五2009年1月30日 - 下午3點10分)

(注:我使用界面生成器創建視圖和loadView方法被註釋掉)

所以,當一個視圖控制器接收到內存警告消息,這些是執行的步驟:

  1. 調用下面的方法:

    - (void)didReceiveMemoryWarning { 
        [super didReceiveMemoryWarning]; 
    } 
    
  2. 呼叫到[super didReceiveMemoryWarning]的結果,[self setView:nil]就會自動叫什麼名字?

  3. 如果應該清除任何資源,則應該覆蓋setView方法以清除本地資源。如果視圖當前處於活動狀態(默認),則不調用[self setView:nil]。對? - 我很好奇哪種方法需要這個決定,以及如何?

您能否確認一下。另外,我收到了一個錯誤,下面是這個方法,但是在中加入myObject = nil後發現dealloc控制器類的方法修復了這個問題。謝謝。

回答

12

這是一個老問題,但我沒有看到一個合適的回答,所以這裏有雲:

當接收到一個內存警告,-didReceiveMemoryWarning被稱爲在所有視圖控制器,無論是「當前」一個或不。視圖控制器只是在監聽內存警告事件廣播。

如果在內存警告時沒有使用視圖控制器的視圖,控制器將通過將該屬性設置爲nil來卸載它。它如何知道該視圖是否被使用?由該視圖的-superview屬性。如果view.superview爲零,則該視圖不是任何樹的一部分,並且可以安全卸載。

一旦發生這種情況,控制器的-viewDidUnload被調用。這是卸載任何店鋪的正確地點,以及任何將在-viewDidLoad中重新創建的地點。


那麼-didReceiveMemoryWarning是什麼?你的控制器可能有一些對象在被訪問之前不會被實例化。例如,您可能有一個控制器,有時需要來自文件的大量數據,但並非總是如此。你可以這樣設置屬性:

- (NSData*)bigChunkOfData { 
    // Get data from our instance variable _data, read from disk if necessary 
    if (_data == nil) { 
    _data = [[NSData alloc] initWithContentsOfFile:@"/path/to/data"]; 
    } 
    return _data; 
} 

這將首次從磁盤讀取數據,然後將其保存在實例變量中。由於_data變量是根據需求創建的,因此我們可以將其卸載到低內存情況下:它會在我們下次需要時再次創建。

- (void)didReceiveMemoryWarning { 
    [super didReceiveMemoryWarning]; 

    [_data release]; 
    _data = nil; // <-- Very important: don't leave strong references dangling. 
} 
8

我做我的清理是這樣的:

-(void)setView:(UIView*)view 
{ 
    [super setView:view]; 
    if(view == nil) 
    { 
     // Our view has been cleared, therefore we should clean up everything 
     // we are not currently using 
.... 

setView:nil由UIViewController的響應內存警告調用,如果這種觀點是當前不可見 - 這基本上是你想知道什麼。

EDITED

在回答如下窗口:

  1. 正確的。
  2. 這就是我所做的,它適用於我。
  3. 正確。在UIViewController中執行didReceiveMemoryWarning是什麼。如果不重寫didReceiveMemoryWarning,那麼在UIViewController中基類的實現將被稱爲 - 如果你重寫它,很明顯你應該叫:

    [super didReceiveMemoryWarning] 
    
+0

即使我不重寫didReceiveMemoryWarning方法,我的觀點被清除。這是爲什麼? – Mustafa 2009-01-30 05:04:01

1

至於視圖管理和內存警告:

UIKit不僅允許從視圖控制器返回導航,還允許從現有視圖導航到其他視圖控制器。 在這種情況下,將分配一個新的UIViewController,然後將其加載到視圖中。 舊的視圖控制器將離開屏幕並變爲非活動狀態,但仍擁有許多對象 - 一些位於自定義屬性和變量中,另一些位於視圖屬性/層次結構中。 對於其視圖對象,新的可見視圖控制器也是如此。

由於移動設備的內存量有限,擁有這兩組對象(一個位於屏幕外視圖控制器和另一個位於屏幕視圖控制器中)可能太多,無法處理。 如果UIKit認爲它是必要的,它可以回收一些關閉屏幕視圖控制器的內存,但不會顯示; UIKit知道哪個視圖控制器在屏幕上,哪個是屏幕外的,畢竟它是管理它們的人(當你撥打presentModalViewController:animated:dismissModalViewControllerAnimated:時)。 因此,每次感覺到壓力時,UIKit會生成一條內存警告,它會從視圖層次結構中卸載並釋放離屏視圖,然後調用您的自定義viewDidUnload方法,以便爲屬性和變量執行相同的操作。 UIKit自動發佈self.view,允許我們手動發佈我們的viewDidUnload代碼中的變量和屬性。 它對所有離屏視圖控制器都這樣。

當系統內存不足時,會觸發didReceiveMemoryWarning。 當屏幕出現內存警告時,屏幕視圖將被回收並釋放,但屏幕視圖不會被釋放 - 它是可見的並且是需要的。 如果您的班級擁有大量內存(如緩存,圖像等),則應該清除didReceiveMemoryWarning,即使它們在屏幕上;否則,您的應用可能會因爲系統資源過剩而終止。 您需要重寫此方法以確保清理內存;只記得你叫[super didReceiveMemoryWarning];

一個更復雜的解釋,請訪問:http://myok12.wordpress.com/2010/11/30/custom-uiviewcontrollers-their-views-and-their-memory-management/

0

幸運的是,模擬器有一個方便的功能,可以讓您將低內存情況加入測試。把一些的NSLog()語句都viewDidLoad中和didReceiveMemoryWarning,像這樣: 

- (void)viewDidLoad { 
    NSLog(@"viewDidLoad"); 
    ... 
} 

- (void)didReceiveMemoryWarning { 
    NSLog(@"didReceiveMemoryWarning"); 
}