在iOS中加载图片的方式有多种,通过OC的方式主要有imageName:和imageWithContentsOfFile:两种。这两种方式如何使用,以及他们之间的区别是什么呢?下面通过两个小示例来详细讲解。
一、imageNamed:和imageWithContentsOfFile:的使用方式
<1>: imageNamed:
新建一个工程,将准备好的图片拖拽到Assets.xcassets文件夹中,具体步骤如下:
来到ViewController.m文件,在viewDidLoad方法中加载图片:
UIImageView *imageView = [[UIImageView alloc] init]; // 创建imageView对象
imageView.frame = CGRectMake(0, 0, 265, 395); // 设置imageView的尺寸
imageView.center = self.view.center; // 让图片在中间位置显示
imageView.image = [UIImage imageNamed:@"1"]; // 加载图片
[self.view addSubview:imageView]; // 显示图片
<2>: imageContentsOfFile:
和上面一样,不过是将图片拖拽到Supporting Files 文件中,如下
需要注意的是,在拖入图片的时候Xcode会弹出一个"Choose options for adding these file"的提示框,一般按照上面默认勾选项就可以了(其中Creat groups 表示在项目中创建虚拟文件夹,而Creat folder references 表示创建实际文件夹),其他的选择项不勾选的话会出错误:
通过imageWithContentOfFile:的方式加载图片资源的代码如下:
UIImageView *imageView = [[UIImageView alloc] init]; // 创建imageView对象
imageView.frame = CGRectMake(0, 0, 265, 395); // 设置imageView的尺寸
imageView.center = self.view.center; // 让图片在中间位置显示
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"0010" ofType:@"jpg"]; // 获取图片资源所在路径
imageView.image = [UIImage imageWithContentsOfFile:imagePath]; // 加载图片
[self.view addSubview:imageView]; // 显示图片
显示效果如下图所示:
二、imageNamed:和imageWithContentsOfFile:的区别。
<1>:打包方式上面的不同
项目完成后,所有的图片资源会被打包成ipa文件发布到AppStore,拖入Assets.xcassets文件夹的图片最后会被打包成一个Assets.car文件,我们不能根据路径读取图片,可以得到一定程度上的保护,以防止盗图(之所以说是一定程度,是因为我们依然可以通过其他手段解压相关图片)。
而拖入Supporting Files文件夹中的图片可以根据路径读取,而拖入Supporting Files文件夹中的图片则直接暴露在外面。可以通过下面一系列图片来验证我们的一些结论(验证方法见:如何快速定位模拟器中的沙盒存放路径):
<2>:出于内存和程序方面的考虑
这里使用一个小程序来验证,首选将准备好的素材拖入到项目中的Aseets.xcassets文件夹中,然后通过imageNamed:方法加载:
// 抽取加载图片重复的代码
- (NSArray *)loadImagesWithImagePrefixName:(NSString *)prefixName count:(int)count {
NSMutableArray<UIImage *> *images = [NSMutableArray array]; // 创建一个可变数组,用于装载图片
for (int i = 0; i < count; i++) {
NSString *imageName = [NSString stringWithFormat:@"%@_%d", prefixName, i + 1];
// 获取图片的名称
NSString *imagePath = [[NSBundle mainBundle] pathForResource:imageName ofType:@"png"];
// 获取图片在资源包中的路径
UIImage *image = [UIImage imageNamed:imageName];
// UIImage *image = [UIImage imageWithContentsOfFile:imagePath]; // 加载图片
[images addObject:image]; // 将图片添加到可变数组中
}
return images; // 返回数组
}
运行程序查看内存使用情况:
我们可以看到在站立的情况下,内存消耗在33.8MB;小招在40M,大招在61.9M,停止状态下仍然保持在61.9M;
理论上讲,我们点击停止按钮以后,保存在数组中的图片资源被清空,内存使用量应该下降,但事实上却并没有:
产生上述问题的主要原因是,通过imageNamed:方法加载的图片,其图片在使用完成后,并不会立即被释放掉,具体释放时间由系统决定。因此,这种加载方法,适用于图片小、数量少,且经常使用的图片处理场合。
通过imageWithContentsOfFile:方法来加载图片。和上面一样,将准备好的素材拖入到项目中,不过这次不是拖入到Assets.xcassets文件夹,而是直接拖入到Supporting Files文件夹中,具体情况如下图所示:
// 抽取加载图片重复的代码
- (NSArray *)loadImagesWithImagePrefixName:(NSString *)prefixName count:(int)count {
NSMutableArray<UIImage *> *images = [NSMutableArray array]; // 创建一个可变数组,用于装载图片
for (int i = 0; i < count; i++) {
NSString *imageName = [NSString stringWithFormat:@"%@_%d", prefixName, i + 1];
// UIImage *image = [UIImage imageNamed:imageName];
// 获取图片的名称
NSString *imagePath = [[NSBundle mainBundle] pathForResource:imageName ofType:@"png"];
// 获取图片在资源包中的路径
// UIImage *image = [UIImage imageWithContentsOfFile:imagePath]; // 加载图片
[images addObject:image]; // 将图片添加到可变数组中
}
return images; // 返回数组
}
点击运行,状态如下:
我们可以看到在站立的情况下,内存消耗在23.4MB;小招在29.7M,大招在51.2M,停止状态下仍然保持在23.5M;可以很明显看到各个状态的内存消耗都要小于imageNamed的那种方式,
尤其是在点击停止按钮以后,保存在数组中的图片资源被清空,内存使用量大幅下降: 这个主要是因为,通过imageWithContentsOfFile:方法加载的图片可以快速的手动释放。
通过这个示例,我们基本上可以总结出imageNamed:和imageWithContentsOfFile:这两个方法的使用场合:
1、imageNamed:方法适用于经常使用,并且图片小、数量少的场合,方便快速加载;
2、imageWithContentsOfFile:方法适用于图片比较大,并且图片数量非常多的场合,此时需要考虑程序的性能。