一、image.xcassets
创建.xcassets(项目创建的时候会默认创建一个 Assets.xcassets文件),以 image set 形式管理图片,每添加一张图片会生成对应的content.json 文件
-
拖入@2x 和 @3x等倍图后,打包以后 以 Assets.car 的形式存在,比如下图:
使用 [UIImage imageNamed:@"xxx"]方式读取图片,相当于创建了一个 key-value字典,key 为图片名,value 为图片对象。创建图片对象后,该对象被加入到NSCache中(解码后的 Image Buffer),同一个图片不会被多次创建,创建一次 会从缓存中获取(不考虑内存警告时的回收),直到收到内存警告的时候才会释放不再使用的图片对象。因此,对于需要在多处显示的图片,使用此方式会减少内存损耗。
二、图片直接加入工程中作为Resource
读取方式:创建图片Resource 文件夹,直接将图片加入到工程中,使用如下方式读取图片:
NSString *path = [NSBundle.mainBundle pathForResource:@"xxx" type:@"png"];
UIImage *image = [UIImage imageWithContentsOfFile:path];
- 特性:在Resource 的图片管理方式中,所有的图片创建都是通过读取文件数据得到的,读取一次文件数据就会产生一次NSData 以及产生一个UIImage。当图片创建好后销毁对应的NSData,当UIImage 的引用计数器变为0的时候自动销毁UIImage,这样的话就可以保证图片不会长期的存在内存中
- 使用场景: 由于这种方法的特性,所以Resource的方法一般用在图片数据很大,图片一般不需要多次使用的情况,比如引导图背景(图片全屏)
- 优势:图片不会长期保存在内存当中,所以不会有很多的内存浪费。同事,大图一般不会长期使用,而且大图占用内存一般比小图多了好多倍,所以在减少大图的内存占用中,Resource做的非常好
三、使用Bundle文件
- Bundle 即资源文件包,将许多图片,xib ,文本文件组织在一起,打包成一个Bundle文件,方便在其他项目中引用保内的资源
- Bundle文件是静态的,不参与项目的编译,Bundle包中不能包含可执行的文件,它仅仅是作为资源,被解析成为特定的二进制数据
- 优势: Bundle中文件不参与项目编译,不影响APP包的大小(可用于包的瘦身);使用Bundle方式方便对文件进行管理,方便在其他项目中引用保内的资源。
- 使用场景: 较大的图片,或者使用频率较低的图片
- 读取方式: 使用imageWithContentsOfFile 进行读取,如下方法1;也可以对UIImage进行扩展,如下方法2
1、使用 imageWithContentsOfFile 读取
#define STBundle_Name @"SafeToolResource.bundle"
#define STBundel_path [[[NSBundle mainBundle ] resouecePath] stringByAppendingPathComponent:STBundle_Name]
#define STBundle [NSBundle bundleWithPath:STBundel_path]
//使用
UIImageView *headerBgImgView = [[UIImageView alloc] init];
headerBgImgView.image = [UIImage imageWithContentsOfFile:[STBundle pathForResource:@"xxx" ofType:@"pne"]];
2、对UIImage 进行扩展,创建UIImage+BSKResources 类
// UIImage + BSKResources.h
@interface UIImage (BSKResources)
+ (UIImage *)bskImageNamed:(NSString *)imageName InBundleName:(NSString *)bundleName;
@end
/// UIImage+BSKResources.m
#import "UIImage+BSKResources.h"
@implementation UIImage (BSKResources)
+ (UIImage *)bskImageNamed:(NSString *)imageName InBundleName:(NSString *)bundleName
{
NSString *resourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:bundleName];
NSBundle *resourceBundle = [NSBundle bundleWithPath:resourcePath];
return [UIImage imageNamed:imageName inBundle: resourceBundle compatibleWithTraitCollection: nil];
}
@end
//使用
UIImageView * headerBgImgView = [[UIImageView alloc] init];
headerBgImgView.image = [UIImage bskImageNamed:@"xxx" InBundleName:@"BSKResources.bundle"]];
四、Bundle 和 xcassets 的区别
- xcassets里面的图片,只能通过imageNamed 加载,bundle 还可以通过imageWithContentsOfFile等方式加载
- xcassets 里面的2x和3x 会根据设备分发,不会同时包含(APP slicing),而bundle 会同时包含
- bundle 内支持多语言,xcassets 不支持
- xcassets内,可以对图片进行slicing,即 裁剪和拉伸,bundle 不支持
- 此外,使用imageNamed 创建的UIImage ,会立即被加入到nscache中,直到收到内存警告的时候才会释放不再使用的UIImage,而使用imageWithContentsOfFile创建的对象,每次都会重新申请内存,相同的图片不会缓存,隐藏建议常用的较小的图放在xcassets内管理,而大图,使用频率较低的图应该放在bundle内管理。