这篇文章是笔者在开发App过程中发现的一些内存问题, 然后学习了YYKit框架时候也发现了图片的缓存处理的不够得当. 以下内容是笔者在开发中做了一些实验以及总结. 如有错误望即时提出, 笔者会第一时间改正.
文章的前篇主要是对两种不同的UIImage
工厂方法的分析, 以及对 YYKit 中的 YYImage 的分析. 罗列出这些工厂方法的内存管理的优缺点.
文章的后篇是本文要说明的重点, 如何结合两种工厂方法的优点做更进一步的节约内存的管理.
PS
本文所说的 Resource 是指使用
imageWithContentsOfFile:
创建图片的图片管理方式.ImageAssets 是指使用
imageNamed:
创建图片的图片管理方式.如果你对这两个方法已经了如指掌, 可以直接看UIImage 与 YYImage 的内存问题和后面的内容
UIImage 的内存处理
在实际的苹果App开发中, 将图片文件导入到工程中无非使用两种方式. 一种是 Resource (我也不知道应该称呼什么,就这么叫吧)
,还有一种是 ImageAssets 形式存储在一个图片资源管理文件中. 这两种方式都可以存储任何形式的图片文件, 但是都有各自的优缺点在内. 接下来我们就来谈谈这两种图片数据管理方式的优缺点.
Resource 与 “imageWithContentsOfFile:”
Resource 的使用方式
将文件直接拖入到工程目录下, 并告诉Xcode打包项目时候把这些图片文件打包进去. 这样在应用的”.app”文件夹中就有这些图片. 在项目中, 读取这些图片可以通过以下方式来获取图片文件并封装成UIImge
对象:
NSString *path = [NSBundle.mainBundle pathForResource:@"image@2x" type:@"png"];
UIImage *image = [UIImage imageWithContentsOfFile:path];
而底层的实现原理近似是:
+ (instancetype)imageWithContentsOfFile:(NSString *)fileName {
NSUInteger scale = 0;
{
scale = 2;//这一部分是取 fileName 中"@"符号后面那个数字, 如果不存在则为1, 这一部分的逻辑省略
}
return [[self alloc] initWithData:[NSData dataWithContentsOfFile:fileName scale:scale];
}
这种方式有一个局限性, 就是图片文件必须在.ipa
的根目录下或者在沙盒中. 在.ipa
的根目录下创建图片文件仅仅只有一种方式, 就是通过 Xcode 把图片文件直接拖入工程中. 还有一种情况也会创建图片文件, 就是当工程支持低版本的 iOS 系统时, 低版本的iOS系统并不支持 ImageAssets 打包文件的图片读取, 所以 Xcode 在编译时候会自动地将 ImageAssets 中的图片复制一份到根目录中. 此时也可以使用这个方法创建图片.
Resource 的特性
在 Resource 的图片管理方式中, 所有的图片创建都是通过读取文件数据得到的, 读取一次文件数据就会产生一次NSData
以及产生一个UIImage
, 当图片创建好后销毁对应的NSData
, 当UIImage
的引用计数器变为0的时候自动销毁UIImage
. 这样的话就可以保证图片不会长期地存在在内存中.
Resource 的常用情景
由于这种方法的特性, 所以 Resource 的方法一般用在图片数据很大, 图片一般不需要多次使用的情况. 比如说引导页背景(图片全屏, 有时候运行APP会显示, 有时候根本就用不到).
Resource 的优点
图片的生命周期可以得到管理无疑是 Resource 最大的优点, 当我们需要图片的时候就创建一个, 当我们不需要这个图片的时候就让他销毁. 图片不会长期的保存在内存当中, 所以不会有很多的内存浪费. 同时, 大图一般不会长期使用, 而且大图占用内存一般比小图多了好多倍, 所以在减少大图的内存占用中, Resource 做的非常好.
ImageAssets 与 “imageNamed:”
ImageAssets 的设计初衷主要是为了自动适配 Retina 屏幕和非 Retina 屏幕, 也就是解决 iPhone 4 和 iPhone 3GS 以及以前机型的屏幕适配问题. 现在 iPhone 3GS 以及之前的机型都已被淘汰, 非 Retina 屏幕已不再是开发考虑的范围. 但是 plus 机型的推出将 Retina 屏幕又提高了一个水平, ImageAssets 现在的主要功能则是区分 plus 屏幕和非 plus 屏幕, 也就是解决 2 倍 Retina 屏幕和 3 倍 Retina 屏幕的视屏问题.