在iOS开发中生成一个UIImage对象的方法通常有两种1.利用imageNamed方法2.使用imageWithContentsOfFile下面介绍这两中方法的区别:

1、imageNamed

imageNamed的优点是可以将已经加载过的图片缓存到内存中。苹果的文档中有如下说法:

This method looks in the system caches for an image object with the
specified name and returns that object if it exists. If a matching image
object is not already in the cache, this method locates and loads the
image data from disk or asset catelog, and then returns the resulting
object. You can not assume that this method is thread safe.

这个方法根据图片名称会先在系统缓存中寻找图片。如果缓存中没有这个图片对象,这个方法会从指定的文件中寻找对应的图片,并将其缓存到内存中。

当你需要重复使用一张图片的时,比如UITableView里的cell需要重复加载一张图片时

最近测试发现使用imageWithContentsOfFile获取保存在应用内的图片的时,内存暴涨,查阅资料后发现,是因为imageWithContentsOfFile没有像imageName具有缓存机制。

在 Apple 官方帮助文档提供了两个加载图片的方法

Apple官方的文档为生成一个UIImage对象提供了两种方法:

[UIImage imageNamed:@"hearderImage"]

2、imageWithContentsOfFile或者imageWithData

这个方法只是简单的加载图片,并不会缓存到内存中。图片会以数据加载到程序中
当不需要重用图片,或者是下载一个很大图片等可以使用该方法
系统不会浪费内存。

imageName
使用这个方法获取图片,首先会先从缓存内获取图片,如果缓存内没有,就从应用内去寻找图片,获取到图片之后,显示图片,并且将图片根据key缓存到缓存池里,下次调用就直接从这里拿,不会再重新获取。

  1. imageNamed , 其参数为图片的名字

  2. imageWithContentsOfFile , 其参数是图片文件的路径 

  1. imageNamed,其参数为图片的名字;

使用这个方法生成的UIImage对象,会在应用的bundle中寻找图片,如果找到则Cache到系统缓存中,作为内存的cache.

imageWithContentsOfFile
这个方法就没有使用到缓存机制,每次都从应用内获取图片,会产生内存,导致内存暴涨。


[UIImage imageNamed:ImageName];

而程序员是无法操作cache的,只能由系统自动处理,如果我们需要重复加载一张图片,那这无疑是一种很好的方式,因为系统能很快的从内存的cache找到这张图片.

下面主要是说一下他们的区别:

  1. imageWithContentsOfFile,其参数也是图片文件的路径。

但是试想,如果加载很多很大的图片的时候,内存消耗过大的时候,就会会强制释放内存,即会遇到内存警告(memory
warnings).由于在iOS系统中释放图片的内存比较麻烦,所以冲易产生内存泄露

imageNamed: 

NSString *thumbnailFile = [[NSBundle mainBundle].resourcePath
stringByAppendingPathComponent:fileName];

小结

imageNamed只适合用于小的图片的读取,或重复使用一张图片的时候,而当加载一些比较大的图片文件的时候我们应当尽量避免使用这个方法.

NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:extension]; UIImage *image = [UIImage imageWithContentsOfFile:filePath];

相比上面的imageNamed这个方法要写的代码多了几行,使用imageWithContentsOfFile的方式加载的图片,图片会被系统以数据的方式进行加载.返回的对象不会保存在缓存中,一旦对象销毁就会释放内存,所以一般不会因为加载图片的方法遇到内存问题.

用这个方法加载图片分为两种情况:

UIImage *thumbnail = [UIImage imageWithContentsOfFile:thumbnailFile];

小结

当有些图片在应用中只使用比较少的次数的,就可以用这样的方式,相比imageNamed会降低内存消耗,避免一些内存问题.

总的来说,写出更好的代码,我们需要权衡代码中所遇到的情况,根据情况选择更好的方法.

  1. 系统缓存有这个图片

    直接从缓存中取得

  2. 系统缓存没有这个图片

    通过传入的文件名对整个工程进行遍历 (在application
    bundle的顶层文件夹寻找名字的图象 ), 如果如果找到对应的图片 , iOS
    系统首先要做的是将这个图片放到系统缓存中去,以备下次使用的时候直接从系统缓存中取
    , 接下来重复第一步,即直接从缓存中取

3.用initWithContentsFile方法

那么试想一下 ,
如果要加载的这个图片的文件量很多,文件大小很大,内存不足,内存泄露,甚至是程序的崩溃都是很容易发生的事.

UIImage *image = [[UIImage alloc]
initWithContentsOfFile:filePath]

[UIImage imageNamed:ImageName];

第一种方法为常见方法,这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象,如果它存在的话。如果缓存中没有找到相应的图片,这个方法从指定的文档中加载然后缓存并返回这个对象。利用它可以方便加载资源图片。用imageNamed的方式加载时,会把图像数据根据它的名字缓存在系统内存中,以提高imageNamed方法获得相同图片的image对象的性能。即使生成的对象被
autoReleasePool释放了,这份缓存也不释放。而且没有明确的释放方法。如果图像比较大,或者图像比较多,用这种方式会消耗很大的内存。

imageWithContentsOfFile 和 initWithContentsOfFile

imageWithContentsOfFile:仅加载图片,图像数据不会缓存。因此对于较大的图片以及使用情况较少时,那就可以用该方法,降低内存消耗。得到的对象是autoRelease的,当autoReleasePool释放时才释放。

用这个方法只有一种情况,那就是仅仅加载图片 , 图像数据不会被缓存 .
因此在加载较大图片的时候 , 以及图片使用情况很少的时候可以使用这两个方法
, 降低内存消耗.

第三种方法要手动release掉。不系统缓存。release后立即释放,一般用在封面等图比较大的地方。

NSString *imageFile = [NSString stringWithFormat:@"%@/%@.jpg", [[NSBundle mainBundle] resourcePath], fileName];
UIImage* image = [UIImage imageWithContentsOfFile:imageFile];

如果想把上述代码简写为一行可以在 pch 文件中定义一个宏,在整个项目中使用

#define ResourcePath(path)  [[NSBundle mainBundle] pathForResource:path ofType:nil]
#define ImageWithPath(path) [UIImage imageWithContentsOfFile:path]

这样就可以一行代码搞定

UIImage* image = ImageWithPath(ResourcePath(@"img.jpg"));

 

总结:

根据各自的优缺点来选择性的使用相应的方法.

  1. 当图片文件较小 , 使用比较频繁的时候那么使用 imageNamed
    比较好.例如:UITableViewCell , UICollectionCell
    等加载同一个图标的时候
    , 在Table里每次利用那个图像的时候,只会把图片指针指向同一块内存。可以直接从缓存中取的数据而不用遍历整个工程.在这种情况下
    imageNamed 的效率还是非常高的.同一个图片对象系统只会把它 Cache
    到内存一次 ,  这对图像的重复利用是非常有优势的.

  2. 你用第二种方式加载的时候 , 图像会被系统以数据的形式加载到程序
    . 当你不需要重用该图像,或者你需要将图像以数据方式存储到数据库,又或者你要通过网络下载一个很大的图像时,请尽量使用imageWithData的方式加载图像。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图