UIViewController阻止视图卸载
当我的iPhone应用程序收到内存警告的UIViewControllers目前不可见的意见得到卸载。 在一个特定的控制器卸载视图和出口是相当致命的。
我正在寻找一种方法来防止这个视图被卸载。 我发现这种行为很愚蠢 – 我有一个caching机制,所以当内存警告来了 – 我卸载自己吨数据,我释放了足够的内存,但我绝对需要这个观点不变。
我看到UIViewController有一个方法unloadViewIfReloadable
,当内存警告来临时被调用。 有谁知道如何告诉Cocoa Touch我的观点是不可重新加载的?
任何其他的build议如何防止我的观点被卸载内存警告?
提前致谢
关于视图控制器视图生命周期的Apple文档说:
didReceiveMemoryWarning – 默认实现只有在确定安全的情况下才会释放视图
现在…我重写didReceiveMemoryWarning
与一个空的函数,只是调用NSLog让我知道收到警告。 然而,视图无论如何都会被卸载。 另外,根据什么标准来决定视图是否可以安全地卸载…哦! 这么多的问题!
什么似乎为我工作是重写setView:
忽略设置为零。 这很糟糕,但是,这是一个非常棘手的问题,
-(void)setView:(UIView*)view { if(view != nil || self.okayToUnloadView) { [super setView:view]; } }
根据文档, didReceiveMemoryWarning的默认实现:释放视图,如果它是安全的(即:superview ==零)。
为了防止视图被释放,你可以重写didReceiveMemoryWarning:但是在你的实现中不要调用 [super didReceiveMemoryWarning]
。 这是视图默认释放的地方(如果不可见)。
默认的[viewcontroller setView:nil]
通过调用[viewcontroller setView:nil]
释放视图,所以你可以改写它。
能这么简单吗?
即使在文档中没有提到这一点,似乎如果我完全保留viewDidLoad中的视图,那么它不会在内存警告中释放。 我试着在模拟器中连续发出几个警告,而且看起来还是不错的。
所以…现在的技巧是在viewDidLoad中“保留”,并在dealloc中释放 – 这样viewcontroller就会被视图卡住,直到需要释放的时候。
我会再testing一下,并写下结果
我不认为这些想法有效。 我尝试覆盖[didReceiveMemoryWarning],这对一些手机,但发现一个手机卸载视图之前,该方法甚至被称为(一定是在极低的内存或东西)工作。 覆盖[setView]产生大量的日志警告,所以我不会冒险苹果。 保留视图只会泄露该视图 – 它将防止崩溃,但不是真正的工作 – 视图将在下次加载控制器UI时被replace。
所以,你真的只需要计划你的观点在任何时候都被卸载了,这是不理想的,但你去。 我发现最好的模式是立即提交,所以你的用户界面始终是最新的,或复制 – 编辑 – 复制,你的模型复制到一个临时的实例,填充你的意见,并立即提交与那么当用户点击“保存”或者其他什么的时候,把修改的内容复制回原来的模型。
因为被接受的解决scheme有问题,即使视图被阻止被清除, viewDidUnload
仍然被调用,我正在使用一个不同但仍然脆弱的方法。 系统使用unloadViewForced:
消息将视图卸载到控制器,所以我拦截该消息以阻止消息。 这可以防止对viewDidUnload
的混淆调用。 代码如下:
@interface UIViewController (Private) - (void)unloadViewForced:(BOOL)forced; @end - (void)unloadViewForced:(BOOL)forced { if (!_safeToUnloadView) { return; } [super unloadViewForced:forced]; }
这有明显的问题,因为它拦截UIViewController中的未logging的消息。
progrmr发布了一个回答,上面build议拦截didReceiveMemoryWarning。 根据我所看到的堆栈跟踪,拦截也应该可行。 我还没有尝试过这样的路由,因为我担心可能有其他内存清理,这也将被阻止(如导致它不调用带有内存警告消息的子视图控制器)。