我有一个视图控制器,有一个私有的NSArray
变量。该变量在viewDidLoad
方法中初始化。当调用didReceiveMemoryWarning
时,会出现几个问题:
- 我应该将私有变量设置为
nil
吗? - 如果我把它设置为
nil
在什么方法必须重新创建?视图控制器是否调用viewDidLoad
方法来重新创建它?
我问是因为视图的其他方法需要这个变量,如果它是nil
将不起作用。
谢谢!
通常通过设置器分配nil
来卸载私有属性(例如self.propertyName = nil
)。或者你可以在调用release后将ivar设置为nil,例如[_propertyName release]; _propertyName = nil;
,但前者更可取。
didReceiveMemoryWarning
方法在内存不足的情况下调用。它被调用在每个视图控制器,包括一个(s)负责当前可见的UI!
因此,当你调用didReceiveMemoryWarning
时,你不能随意卸载数据——视图控制器可能需要当前在显示器上可见的数据。
一般的原则是,didReceiveMemoryWarning
可以摆脱任何资源,它可以帮助释放内存,但只有那些不是立即需要的。例如,在OpenGL游戏中,你不会卸载当前在显示器上可见的纹理。但是,请看我的最后一段。
通常在需要的时候检查资源是否加载,如果没有加载,就加载它们。
不值得放置/释放像单个正常大小的字符串这样的小资源。你应该把注意力集中在占用大量内存的项目上。
最近在后台内存管理方面的进展意味着你不太可能需要实际卸载数据——操作系统可以在后台卸载和重新加载未压缩的图像数据等。
正如Hot Licks提到的,模拟器有一个模拟内存警告的选项。在你的应用程序的不同点触发这个内存警告是值得的,看看它是如何表现的。
创建延迟加载数据的自定义getter。下面的代码片段适合于非多线程环境:
- (NSArray*) dataArray {
if(_dataArray) return _dataArray;
_dataArray = [self lordata];
return _dataArray;
}
这样,如果在内存中"释放"数据,则总是会重新加载数据。
ViewDidLoad
方法只被调用一次,当你的ViewController被初始化。如果你必须重新加载一些数据到你的NSArray,你应该在需要的时候调用你自己的方法来完成。
如果这个数组被代码的各个部分使用,也许你应该考虑重新设计你的代码结构,以避免大量的数据集中在一个对象中。
编辑:正如@occulus在下面的评论中指出的,它不是在视图初始化时调用的,而是在视图被ViewController加载时调用的。我的错误
作为一个例子,我有一个应用程序,下载数据到一个非常长的表视图(可能有1000条记录)。为了支持这一点,我实现了一个"稀疏"数组,允许空元素在被引用时在网络上"故障"(在下载时在表单元格中有一个"下载"指示符)。
当didReceiveMemoryWarning发生时,数组将被清除,使用最近最少使用的算法删除数组中最老的N%。恢复将是自动的——清空的单元格将在它们被引用时重新加载。
我并不是推荐这种特殊的方案,但请注意具有大量数据的一般特性,有一种方法来"优先考虑"应该删除的内容,以及有一种"软"方式来重新加载数据(理想情况下,只重新加载近期需要的部分)。
最好将变量设置为nil。我的意思是释放它在didReceiveMemoryWarning
中所占用的内存,并设置一个脏标志。
你总是可以在数组的getter(你可以自己写)中检查dirty标志并重新填充它。这可能不是最好的办法。这完全取决于数组的使用。