问题:描述memory warning的机制,并列举出APP应该做什么来防止?
答:系统有四种内存警告,定义如下:
Typedef enum {
OSMemoryNotificationLevelAny = -1,
OSMemoryNotificationLevelNormal = 0,
OSMemoryNotificationLevelWarning = 1,
OSMemoryNotificationLevelUrgent = 2,
OSMemoryNotificationLevelCritical = 3,
}OSMemoryNotificationLevel;
通常我们在程序中接收到最多的就是Memory warning level1,这个时候就证明系统内存紧张了,我们的程序必须做出响应,释放不必要的内存。通常如果我们处理得当的话,内存警告就会到此停止,恢复正常状态。如果我们在接收到memory warning level1以后坐视不理的话,系统可能还会再尝试通知几次level1,如果还是不去处理的话,系统将会发出更高一级的内存警告level2,通常的结果就是我们的App被强制退出,系统收回内存。当然系统在发出level2的警告时,也会去做一些清理内存的事,例如关闭不必要的后台程序等。很显然我们不该寄希望于系统自己清理,这就好比你的胳膊被划破了,身体肯定会有自修复功能,但是如果伤口比较大的话,肯定还是需要人工处理一下的。
到目前为止,我还没用见过level3的警告,根据stackoverflow上面讲的“当发生level3警告时,系统内核将会接管,很有可能关掉IOS的主界面进程(SpringBoard),甚至会重启”,按照这个意思来说,我们程序里面接收不到,也实属正常,系统自己的东西都被干掉了,我们肯定早被kill了。
iPhone中每个app可用的内存是被限制的,如果一个app使用的内存超过20M,则系统会向该app发送memory warning消息。收到此消息后,app必须正确处理,否则可能出错或者出现内存泄露。
App收到memory warning后会调用:
UIApplication::didReceiveMemoryWarning->UIApplicationDelegate::applicationDidReceiveMemoryWarning,然后调用当前所有的viewController进行处理。因此处理的主要工作是在viewController。
我们知道,创建viewController时,执行顺序是loadview->viewDidLoad。
当收到内存警告时,如果viewController未显示(在后台),会执行didReceiveMemoryWarning->viewDidUnLoad;如果viewController当前正在显示(在前台),则只执行didReceiveMemoryWarning。
当重新显示该viewController时,执行过viewDidUnLoad的viewController(即原来在后台)会重新调用loadView->viewDidLoad。
因此主要注意下面几个函数:
loadView:创建view,构建界面;
viewDidLoad:做一些初始化工作。由于在初次创建viewController和重新恢复时都会调用,因此这个函数要注意区分不同的情况,设置正确的状态。
didReceiMemoryWarning:释放不必要的内存,比如缓存,未显示的view等。
viewDidUnLoad:最大程度的释放可以释放的内存。比如应该释放view,这些view在调用loadView后可以重新生成。(其中成员变量释放后应设置为nil)。对于非界面的数据是否释放,要具体分析,可以恢复的数据可以释放,不能恢复的数据就不要释放。
实际中,如果viewController是用xib生成的界面,则要我们做的就比较少,主要是在viewDidLoad中恢复原来的界面状态。
如果是通过编程创建的界面,则要做的工作就要更多些,上面的4个函数中都要进行正确处理。