音效素材网提供各类素材,打造精品素材网站!

站内导航 站长工具 投稿中心 手机访问

音效素材

深入分析iOS应用中对于图片缓存的管理和使用
日期:2016-04-05 09:19:43   来源:脚本之家

我们的 iOS 应用都包含了大量的图像。创建富有吸引力的视图,主要依赖于大量的装饰图片,所有这些首先必须从远程服务器获取。如果每次打开应用都要从服务器一次又一次的获取每个图像,那么用户体验肯定达不到好的效果,所以本地缓存远程图像是非常有必要的。

两种方式加载本地图片
1.通过imageNamed:方法加载图片
用过这种方式加载图片,一旦图片加载到内存中,那么就不会销毁,一直到程序退出。(也就是说imageNamed:会有图片缓存的功能,当下次访问图片的时候速度会更快。)
用这种方式加载图片,图片的内存管理并不受程序员控制。

复制代码 代码如下:

UIImage *image = [UIImage imageNamed: @“image”]

的意思是创建一个UIImage对象,并不是说image这个本身就是一张图片,而是image指向一张图片。在创建这个对象的时候实际上并没有把真正的图片加载到内存里,而是等到用到图片的时候才会加载。
如上例,如果把image对象设置为nil,如果是其它对象,那么没有强指针指向一个对象,这个对象就会销毁;但是即使image = nil,它会指向的图片资源也不会销毁。
2.通过imageWithContentsOfFile:方式加载图片
使用这个方法加载图片,当指向图片对象的指针销毁或指向其它对象,这个图片对象没有其它强指针指向,这个图片对象会销毁,不会一直在内存中停留。

因为没有缓存,所以如果相同的图片多次加载,那么也会有多个图片对象来占用内存,而不是用缓存的图片。

使用这个方法,需要file的全路径(之前用NSString, NSArray之类的加载文件也是一样的,比如stringWithContentsOfFile:,看到file就知道是需要传入全路径。)

复制代码 代码如下:

NSString *imagePath = [[NSBundle mainBundle] pathForResource:imageName ofType:@"png"];
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];

注意如果图片在Images.xcassets中,是不能使用这个方法的。所以说想要自己进行图片的内存管理(不希望有缓存图片),那么要将图片资源直接拖入工程,而不是放在Images.xcassets中。


快速队列和慢速队列
我们设置了两个队列,一个串行,一个并行。在屏幕上被迫切要求的图片进入并行队列(fastQueue),可能晚点才需要的图片进入串行队列(slowQueue)。
就UITableView的实现而言,这意味着在屏幕上的表格单元从fastQueue获取图片, 每个关闭的屏幕行的图片从slowQueue预加载。

现在不需要处理图片

假设我们要从服务器上请求包含30条事件的一页资讯回来,一旦这些内容请求回来时我们就可以排队等待预取其中的每一张图。

复制代码 代码如下:

- (void)pageLoaded:(NSArray *)newEvents {   
    for (SGEvent *event in newEvents) {       
       [SGImageCache slowGetImageForURL:event.imageURL thenDo:nil];   
    }
}

slowGetImageForURL:这个方法将图片添加到slowQueue这个队列当中,允许它们在不阻塞网络通信的前提下被一张一张的取出来。
thenDo:这个代码块在这里是没有被实现,是因为我们目前还不需要对图片做任何事情。所有我们需要做的就是确保它们在本地磁盘缓存当中,并且随时准备在屏幕上滑动表格时来使用。

现在就要处理图片

显示在屏幕上的表格希望立即显示它们的图片,所以在table cell子类当中实现:

复制代码 代码如下:

- (void)setEvent:(SGEvent *)event {   
    __weak SGEventCell *me = self;   
    [SGImageCache getImageForURL:event.imageURL thenDo:^(UIImage *image) {       
       me.imageView.image = image;    }
    ];
}

getImageForURL:这个方法将抓取图片的过程添加到fastQueue这个队列当中,意味着只要iOS系统允许,它们会并行被地执行。如果抓取图片的过程已经存在于slowQueue队列当中,它会被移动到fastQueue队列中,从而避免重复请求。

一直异步

等等,getImageForURL:不是一个异步方法吗?如果你明知道图片已经在缓存中,但是却不想在主线程上立即使用它吗?直觉告诉你那是错误的。
从磁盘上加载图片太费资源,同样解压图片也会费很多资源。可以在滑动的过程当中进行配置和添加表格,这最后一件你想在滑动表格时做的事是很危险地,因为它会阻塞主线程,会有卡顿的现象出现。
使用getImageForURL:可以让磁盘加载的动作脱离主线程,于是当thenDo:这个用于收尾工作的代码块执行的时候它已经有了一个UIImage实例,从而不会有滑动卡顿的危险。如果图片已经存在于本地缓存当中,用于收尾工作的代码块会在下一次运行周期执行,并且用户不会注意到两者之间的差别。他们会注意到的是滑动不会卡顿了。

现在,不需要你快速执行

如果用户很快的滑动表格到底部,几十或几百个表格单元会出现在屏幕上,并向fastQueue请求图片数据,然后很快地从屏幕上消失。突然间这个并行地队列会将大量实际上不再需要的图片请求充斥进网络。当用户最终停止滑动时,那些当前屏幕上相应的表格单元视图会将它们的图片请求至于那些并不急需的请求后面,因此网络阻塞了。
这就是 wheremoveTaskToSlowQueueForURL:这个方法的产生的原因.

复制代码 代码如下:

// a table cell is going off screen-
(void)tableView:(UITableView *)table       
didEndDisplayingCell:(UITableViewCell *)cell       
forRowAtIndexPath:(NSIndexPath*)indexPath {   
     // we don't need it right now, so move it to the slow queue            
     [SGImageCache moveTaskToSlowQueueForURL:[[(id)cell event] imageURL]];
}

这确保在fastQueue中的只会有真正需要被快速执行的任务。任何以前认为需要快速执行但现在不需要的任务会被移至slowQueue中。

重点和选择

已经有相当多的iOS图片缓存库。它们中一些库只针对某些应用场景,一些库提供了不同场景一定的可扩展性。我们的库即没有专门针对某些应用场景,也没有太多大而全的特性。针对我们的用户我们有三类基本的重点:
重点 1: 最好的帧率
很多的库都非常专注在这一点上,使用一些高度定制和复杂的方法,尽管基准没有决定性地显示这样有效。我们发现最好的帧率由这些决定:
将对磁盘的访问(并且几乎其它的所有)脱离主线程。
使用UIImage的内存缓存来避免不必要的磁盘访问和图片解压。

重点 2: 让最最重要的图片优先显示
大多数的库都考虑让队列管理成为别人关心的事。对于我们的应用,这几乎是最重要的点。
让正确的图片在正确的时间显示在屏幕上可以归结为一个简单的问题:“我们现在就需要它显示还是过一会儿?”。那些需要立即显示的图片是并行加载地,而其它所有东西都被添加到串行队列中。所有之前急迫的事但现在不急迫的话就会从fastQueue分到slowQueue中。并且当fastQueue在工作时,slowQueue是处于挂起状态的。
这让那些急需显示的图片可以单独访问网络,同时也确保了一张非急需显示的图片可以在过一会成为一张急需显示的图片,因为它已经存到了缓存当中,随时准备用于显示。

重点 3: 尽可能简单的API
大多数库都做到了这一点。许多库为了隐藏细节内容而提供了UIImageView的分类,并且许多库让抓取一张图片的流程变得尽可能的便利。针对我们经常做的三件事,我们的库选定了三个主要的方法:
快速抓到一张图

复制代码 代码如下:

__weak SGEventCell *me = self;[SGImageCache getImageForURL:event.imageURL thenDo:^(UIImage *image) {    me.imageView.image = image;}];

排队等待一张我们一会才需要的图片
复制代码 代码如下:

[SGImageCache slowGetImageForURL:event.imageURL thenDo:nil];

通知缓存一张急需显示的图已经不需要立刻显示
复制代码 代码如下:

[SGImageCache moveTaskToSlowQueueForURL:event.imageURL];

结论

通过专注于预取,队列管理,从主线程移除耗时的任务,并且依赖于UIImage内置的内存缓存,我们努力从一个简单的软件包中得到好的结果。

    您感兴趣的教程

    在docker中安装mysql详解

    本篇文章主要介绍了在docker中安装mysql详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编...

    详解 安装 docker mysql

    win10中文输入法仅在桌面显示怎么办?

    win10中文输入法仅在桌面显示怎么办?

    win10系统使用搜狗,QQ输入法只有在显示桌面的时候才出来,在使用其他程序输入框里面却只能输入字母数字,win10中...

    win10 中文输入法

    一分钟掌握linux系统目录结构

    这篇文章主要介绍了linux系统目录结构,通过结构图和多张表格了解linux系统目录结构,感兴趣的小伙伴们可以参考一...

    结构 目录 系统 linux

    PHP程序员玩转Linux系列 Linux和Windows安装

    这篇文章主要为大家详细介绍了PHP程序员玩转Linux系列文章,Linux和Windows安装nginx教程,具有一定的参考价值,感兴趣...

    玩转 程序员 安装 系列 PHP

    win10怎么安装杜比音效Doby V4.1 win10安装杜

    第四代杜比®家庭影院®技术包含了一整套协同工作的技术,让PC 发出清晰的环绕声同时第四代杜比家庭影院技术...

    win10杜比音效

    纯CSS实现iOS风格打开关闭选择框功能

    这篇文章主要介绍了纯CSS实现iOS风格打开关闭选择框,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作...

    css ios c

    Win7如何给C盘扩容 Win7系统电脑C盘扩容的办法

    Win7如何给C盘扩容 Win7系统电脑C盘扩容的

    Win7给电脑C盘扩容的办法大家知道吗?当系统分区C盘空间不足时,就需要给它扩容了,如果不管,C盘没有足够的空间...

    Win7 C盘 扩容

    百度推广竞品词的投放策略

    SEM是基于关键词搜索的营销活动。作为推广人员,我们所做的工作,就是打理成千上万的关键词,关注它们的质量度...

    百度推广 竞品词

    Visual Studio Code(vscode) git的使用教程

    这篇文章主要介绍了详解Visual Studio Code(vscode) git的使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...

    教程 Studio Visual Code git

    七牛云储存创始人分享七牛的创立故事与

    这篇文章主要介绍了七牛云储存创始人分享七牛的创立故事与对Go语言的应用,七牛选用Go语言这门新兴的编程语言进行...

    七牛 Go语言

    Win10预览版Mobile 10547即将发布 9月19日上午

    微软副总裁Gabriel Aul的Twitter透露了 Win10 Mobile预览版10536即将发布,他表示该版本已进入内部慢速版阶段,发布时间目...

    Win10 预览版

    HTML标签meta总结,HTML5 head meta 属性整理

    移动前端开发中添加一些webkit专属的HTML5头部标签,帮助浏览器更好解析HTML代码,更好地将移动web前端页面表现出来...

    移动端html5模拟长按事件的实现方法

    这篇文章主要介绍了移动端html5模拟长按事件的实现方法的相关资料,小编觉得挺不错的,现在分享给大家,也给大家...

    移动端 html5 长按

    HTML常用meta大全(推荐)

    这篇文章主要介绍了HTML常用meta大全(推荐),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参...

    cdr怎么把图片转换成位图? cdr图片转换为位图的教程

    cdr怎么把图片转换成位图? cdr图片转换为

    cdr怎么把图片转换成位图?cdr中插入的图片想要转换成位图,该怎么转换呢?下面我们就来看看cdr图片转换为位图的...

    cdr 图片 位图

    win10系统怎么录屏?win10系统自带录屏详细教程

    win10系统怎么录屏?win10系统自带录屏详细

    当我们是使用win10系统的时候,想要录制电脑上的画面,这时候有人会想到下个第三方软件,其实可以用电脑上的自带...

    win10 系统自带录屏 详细教程

    + 更多教程 +
    Windows系统Linux系统苹果MACAndroidiOS系统鸿蒙系统