当前位置:  开发笔记 > IOS > 正文

Objective C中的实例缓存

如何解决《ObjectiveC中的实例缓存》经验,为你挑选了2个好方法。

我想缓存某个类的实例.该类保留其所有实例的字典,当有人请求新实例时,该类首先尝试从缓存中满足请求.但是内存管理存在一个小问题:字典缓存保留了插入的对象,因此它们永远不会被释放.我确实希望它们被解除分配,因此我不得不重载该release方法,当保留计数降为1时,我可以从缓存中删除该实例并让它被释放.

这是有效的,但我不喜欢弄乱release方法,并发现解决方案过于复杂.我以为我可以使用一些不保留它存储的对象的散列类.有这样的吗?这个想法是当某个实例的最后一个用户释放它时,该实例将自动从缓存中消失.

NSHashTable似乎是我正在寻找的,但文档谈到"在垃圾收集环境中支持弱关系."它是否也可以在没有垃圾收集的情况下工作?


澄清:我不能将实例保留在内存中,除非有人真正需要它们,这就是为什么我想在最后一个"真实"用户释放它时从缓存中清除实例的原因.


更好的解决方案:这是在iPhone上,我想缓存一些纹理,另一方面,我想在最后一个真正的持有者发布它们时立即将它们从内存中释放出来.编写代码的更简单方法是通过另一个类(让我们称之为TextureManager).此类管理纹理实例并对其进行缓存,以便从缓存中提供后续对具有相同名称的纹理的调用.当最后一个用户释放纹理时,无需立即清除缓存.我们可以简单地将纹理缓存在内存中,当设备内存不足时,我们会收到低内存警告并可以清除缓存.这是一个更好的解决方案,因为缓存内容不污染Texture类,我们不必乱用release,甚至更高的缓存命中机会.该TextureManager可以抽象为a ResourceManager,这样它就可以缓存其他数据,而不仅仅是纹理.



1> Louis Gerbar..:

是的,您可以使用NSHashTable构建本质上非保留字典.或者,您可以使用NULL调用CFDictionaryCreate进行发布并保留回调.然后,您可以简单地将结果类型转换为NSDictionary,这要归功于tollfree桥接,并且使用它就像普通的NSDictionary一样,除了没有摆弄保留计数.

如果这样做,字典将不会自动将引用归零,您需要确保在取消分配实例时将其删除.



2> Analog File..:

你想要的是归零弱引用(它不是"高速缓存管理算法的Graal",它是一个众所周知的模式).问题是,Objective C仅在使用垃圾收集运行时为您提供归零弱引用,而不是在手动内存管理程序中.iPhone还没有提供垃圾收集.

到目前为止,所有答案似乎都指向了半解决方案.

使用非重新连接引用是不够的,因为在释放引用的对象时,您需要将其清零(或从字典中删除条目).但是,必须在调用该对象的-dealloc方法之前完成此操作,否则缓存的存在会使您面临复制对象的风险.执行此操作的方法是在创建弱引用时动态子类化对象,并在动态创建的子类中重写-release以使用锁定和-dealloc将弱引用清零.

这通常有效,但对于免费桥接的Core Foundation对象来说它很难失败.不幸的是,唯一的解决方案,如果你需要将技术扩展到免费的桥接对象,需要一些黑客和未记录的东西(参见这里的代码和解释),因此不适用于iOS或你想在其上销售的程序Mac App Store.

如果您需要在Apple商店销售并因此必须避免未记录的内容,那么您最好的选择是实现对保留缓存的锁定访问,然后在您希望释放内存时清除当前-retainCount值为1的引用.只要所有对缓存的访问都是在保持锁定的情况下完成的,如果在按住锁定时观察到计数为1,您就会知道如果从缓存中删除该对象,则无法复活该对象(因此将其释放)在放弃锁之前.

对于iOS,您可以使用UIApplicationDidReceiveMemoryWarningNotification来触发清理.在mac上你需要实现自己的逻辑:可能只是一个定期检查,甚至只是一个定期清理(这两个解决方案也适用于iOS).

推荐阅读
刘美娥94662
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有