NSCache 整理

这两天在查内存占用的问题,发现瀑布流下拉刷新一次就会增长40~50M 左右的内存,内存增长的很快,最后发现是SDWebimage 增加的内存,由于下载的图片是原尺寸的图片导致,一张图片大约增加内测8M 左右,然后手动调用了一下 SDWebimage 的内存缓存清理方法,内存就降下来了。

看了几篇文章说需要清理 SDWebimage 来清理内存。

天天都在用的 SDWebImage, 你了解它的缓存策略吗?

SDWebImage内存飙升导致crash

使用SDWebImage加载大量图片后造成内存泄露的解决办法

完美解决SDWebImage加载多个图片内存崩溃的问题

觉得我们也应该清理一下 SDWebimage 的内存。

早上跟同事商量了一下,他们说 SDWebimage 是使用的NSCache 做为缓存的,它是线程安全的并且会在内存报警的时候释放自动释放掉,不需要自己管理,而且加载原图也是为了在展示视频的时候可以先把封面图拿过来展示。

尴尬,自己为什么不知道,以前欠下的债还是要还的,以后还是要多补基础知识。

看了几篇介绍 NSCache 的文章。

NSCache

Foundation: NSCache

NSCache

对NSCache的一些理解

我们应该使用的NSCache

使用NSCache构建缓存,而非NSDictionary

iOS系统中缓存的使用

发现一个好玩的东西NSPurgeableData

这里有个NSPurgeableData类型比较有意思,是NSMutableData的子类,和NSCache联合使用可以在NSPurgeableData内存释放时候自动清除缓存。


NSCache类声明中还有一个evictsObjectsWithDiscardedContent的属性。该属性为了搭配NSPurgeableData对象而添加的。

NSPurgeableData是NSMutableData的子类,实现了NSDiscardableContent协议。该协议声明如下:

@protocol NSDiscardableContent
@required
- (BOOL)beginContentAccess;
- (void)endContentAccess;
- (void)discardContentIfPossible;
- (BOOL)isContentDiscarded;
@end
如果某个对象实现了该协议所定义的接口,该对象所占的内存就可以根据需要随时丢弃。而NSPurgeableData实现了该协议就意味着,当系统资源紧张时,可以把保存NSPurgeableData对象那块内存释放掉。

如果需要访问NSPurgeableData对象,调用其beginContentAccess方法,告诉它现在还不应该丢弃自己所占有的内存。用完之后,调用endContentAccess方法,告诉它在必要时可以丢弃自己所占据的内存。这就像retain和release类似来管理,只有当NSPurgeableData中purge引用计数为0时才可以丢弃。purge引用计数,会在创建时加1,非常像真正的引用计数管理规则。

isContentDiscarded是查询对象内存是否被释放。

那么,NSPurgeableData对象假如加入到NSCache中,那么当该对象被系统丢弃时,也会自动从缓存中移除。而上面提到的NSCache中的evictsObjectsWithDiscardedContent属性,就是是否要开启这个功能的开关。

另外看到一点关于load的说明

load方法:对于运行期系统的每个类(class)及分类(category),都必调用且仅调用一次。

基本调用顺序就是,执行当前类的load方法,必定先调用super的load方法,如果代码依赖其他程序库,那么程序库中得相关类的load方法也会先执行。类load方法执行完成后,会执行相应的分类的load的方法。
但是如果在一个程序库中得若干个class,却没法确定load顺序,所以load方法不建议使用其他class。
load方法在调用的时候,app会阻塞,所以一定要轻!
应用程序会阻塞并把所有类的load方法都执行完,才能继续。

load方法直接使用函数内存地址的方式(*load_method)(cls, SEL_load)调用的,而不是使用发送消息 objc_msgSend 的方式。
因此:load方法不遵循继承规则:如果一个class本身没有实现load方法,那么无论其各级super是否实现load,都不会调用;
同时:当一个类和它的分类都实现了 +load 方法时,两个方法都会被调用。
所以:像method swizzling这种操作会放在load里面进行。

load方法调用时,程序甚至没有autoreleasepool

initialize方法:首次使用该class前调用,且只有1次。

和load方法相比,他是“lazy”调用的,也就是类或它的子类收到第一条消息之前被调用的,这里所指的消息包括实例方法和类方法的调用。。
可以安全使用任何class,因为它们都已经load过了。
initialize方法执行一定在thread-safe environment,也就是说会阻塞所有线程。
initialize会走和objc_msgSend一样的消息发送原则,也就是会有覆盖。
实际编译器调用时,父类的会优先于子类调用。