2010-06-03 106 views
16

當我的iPhone應用程序收到內存警告時,當前不可見的UIViewControllers視圖將被卸載。在一個特定的控制器卸載視圖和出口是相當致命的。UIViewController阻止卸載視圖

我正在尋找一種方法來防止此視圖被卸載。我發現這種行爲非常愚蠢 - 我有一個緩存機制,所以當內存警告來臨時 - 我卸載了大量數據,並釋放了足夠的內存,但我絕對需要這個視圖。

我看到UIViewController有一個方法unloadViewIfReloadable,它會在內存警告來臨時調用。有人知道如何告訴Cocoa Touch我的視圖不可重新加載嗎?

任何其他建議如何防止我的視圖被卸載內存警告?

在此先感謝


約視圖控制器的視圖生命週期

蘋果的文檔說:

didReceiveMemoryWarning - 默認 實現釋放的觀點僅 如果確定它是安全可靠 so

現在...我用一個空函數覆蓋didReceiveMemoryWarning,它只是調用NSLog讓我知道收到了一個警告。但是 - 視圖無論如何都會被卸載。另外,根據什麼標準來決定視圖是否可以安全地卸載......哦!這麼多的問題!

+0

也許你應該重構你的設計,以便不能被釋放的部分是單獨的持久對象的一部分,而不是視圖本身的一部分。 – 2010-06-03 11:44:23

+0

嗨大衛,在屏幕上顯示的整個視圖層次結構,我不想撕掉它,然後再次構建它,而我在頂部顯示模態視圖控制器...是不是過度殺傷? – 2010-06-03 11:56:20

+2

我喜歡@umpo提供的解決方案,但是,這些代碼會導致運行時警告,像'MyViewController實現-viewDidUnload導致視圖重新加載。 這會對系統性能產生不利影響。「 - 你是忽略它還是你做了些什麼? – matm 2011-06-28 13:29:26

回答

13

什麼似乎是我的工作是覆蓋setView:忽略設置爲零。它的缺憾,不過呢,這是一個缺憾問題,這並獲得成功:

-(void)setView:(UIView*)view { 
    if(view != nil || self.okayToUnloadView) { 
     [super setView:view]; 
    } 
} 
+0

哇......這就是我稱之爲「在盒子外面思考」的感謝,當我滾動我的應用程序的下一次更新時,我將實施該 – 2011-02-25 10:47:29

+1

只是一個通知 - 我實現了這一點 - 3個應用程序現在使用它在App商店,對我來說,解決方案正常工作 – 2011-06-22 07:54:56

+0

這個問題是,viewDidUnload方法仍然被調用,如果你不小心,可能會混淆你的代碼。我懷疑這就是爲什麼有些人看到有關不良表現的警告。 – 2012-01-02 22:59:11

1

它會這麼簡單嗎?

儘管在文檔中沒有提到這一點,但如果我只在viewDidLoad中保留我的視圖,那麼它在內存警告中不會被釋放。我在模擬器中嘗試了幾次連續的警告,而且所有警告看起來都不錯。

所以......現在的技巧是在viewDidLoad中「保留」,並在dealloc中發佈 - 這樣viewcontroller就會與視圖「卡在一起」,直到它需要被釋放。

我會測試多一些,並寫結果

+0

這個伎倆似乎不適合我。直接調用Dealloc,無論如何都會卸載視圖。我也試圖用[自我保留];而這只是讓它無休止地嘗試去分配。不知道爲什麼。 – jocull 2010-12-03 21:54:02

15

按照文檔的didReceiveMemoryWarning:版本中,如果是安全的做圖的默認實現(即:上海華==無)。

爲防止視圖被釋放,您可以覆蓋didReceiveMemoryWarning:但在您的實施中請勿撥打[super didReceiveMemoryWarning]。這就是視圖默認釋放的地方(如果不可見)。

默認didReceiveMemoryWarning通過調用[viewcontroller setView:nil]來釋放視圖,因此您可以改寫它。

+0

覆蓋didReceiveMemoryWarning對我沒有任何影響。重寫setView會使調試控制檯抱怨整個過程會對性能產生不利影響。這是否會讓你離開應用商店? – jocull 2010-12-03 22:07:54

1

我不認爲任何這些工作思路。我嘗試覆蓋[didReceiveMemoryWarning],這對一些手機有效,但發現一個手機在該方法甚至被調用之前卸載了視圖(必須在極低內存或某些內存中)。覆蓋[setView]會產生大量的日誌警告,所以我不會冒險通過Apple。保留視圖只會泄露該視圖 - 它可以防止崩潰,但不會真正起作用 - 視圖將在下次加載控制器UI時被替換。

所以你真的只需要計劃你的視圖在任何時候被卸載,這是不理想的,但你去。我發現可以使用的最佳模式是立即提交,因此您的用戶界面始終是最新版本或複製編輯副本,您可以在其中將模型複製到臨時實例,填充視圖並立即使用該實例,然後在用戶點擊「保存」或其他內容時將更改複製回原始模型。

+1

爲我重寫setView:方法完美工作,不會產生警告,我已經有3個應用程序使用這種技術的應用程序商店 – 2011-06-22 07:53:49

+0

不幸的是,沒有做任何事情來解決空白白屏幕,當模式視圖被解僱時將迎接用戶揭示潛在的空洞觀點。 – Oscar 2012-02-29 03:50:18

1

由於即使視圖被阻止清除,接受的解決方案仍存在問題,因此viewDidUnload仍在調用,但我使用了一種不同但仍然脆弱的方法。系統使用unloadViewForced:消息將視圖卸載到控制器,以攔截該消息。這可以防止對viewDidUnload的混淆呼叫。這裏的代碼:

@interface UIViewController (Private) 
- (void)unloadViewForced:(BOOL)forced; 
@end 

- (void)unloadViewForced:(BOOL)forced { 
    if (!_safeToUnloadView) { 
     return; 
    } 
    [super unloadViewForced:forced]; 
} 

這有明顯的問題,因爲它攔截UIViewController中的未記錄的消息。

progrmr發佈了一個回答,上面建議攔截didReceiveMemoryWarning。根據我所看到的堆棧跟蹤,攔截該應該也可以。我還沒有嘗試過這個路由,因爲我擔心可能會有其他內存清理,這些內存清理也會被阻塞(例如導致它不會使用內存警告消息調用子視圖控制器)。

+0

你在哪裏指定'UIViewController'的類別?在'.m'文件中?出於某種原因,我的重載'unloadViewForced'永遠不會被調用。 – expert 2013-09-09 02:15:51

+0

是的,在.m文件中。 – 2013-09-13 21:32:56

+0

我還沒有檢查過它是否停止使用任何最新的iOS更新。由於它是一個無證API,它可能已經消失或被重命名。 – 2013-09-13 21:39:32