一款轻量级的 iOS 图像缓存

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

叶秀兰
翻译于 1年前

0人顶

 翻译的不错哦!

版本1-寻找一张图片,并从磁盘上读取它

我们的第一个图片缓存是简单但是有效的。从缓存中寻找每一个我们曾经访问过的图片,用远程的URL作为缓存的键值。如果本地的磁盘缓存时有效的,从磁盘中读取文件并创建UIImage,并立即返回。如果再磁盘上没有找到文件,异步的从远程URL获取文件,缓存到磁盘,然后返回一个新建的UIImage。

目前这对于我们的使用是完全满足了。但是它有一个不必要的弱点:每次缓存请求都需要从磁盘读取图片,性能都消耗在对磁盘的访问和图片文件的解码上了。

地狱星星
翻译于 1年前

0人顶

 翻译的不错哦!

版本 2 - 內存缓存

谢天谢地,苹果的UIImage有内置的内存缓存。所以,你只需修改一行代码,图片就能从磁盘缓存改为内存缓存。

当你使用imageNamed:获取UIImage的时候,它第一步就是检查自己的内存看看是否已经加载过这个图片。如果这样,你不用任何系统花销就能得到一个UIImage实例。所以把原本这样的写法替换掉:

return [UIImage imageWithContentsOfFile:[self absolutePathForURL:url]];

我们可以零花销去访问内存缓存,用下面的代码就可以了:

return [UIImage imageNamed:[self relativePathForURL:url]];

UIImage  会查找它的内存缓存,如果找到,就会零消耗地返回这个照片. 如果没有找到,这张照片就会从磁盘加载,消耗一定的系统性能。

美其名曰
翻译于 1年前

0人顶

 翻译的不错哦!

版本3 —— 获取队列、数据预取和变量催促

当改进应用程序设计时我们渴望更多的图片元素,渴望更炫的画面,更大的图片,更多的图片。

让这些大图尽可能快的显示在屏幕上对用户体验来说是至关重要的,而只是简单地在每次需要显示的时候去缓存当中抓取图片数据是不能够解决问题的。大图需要更多的时间才能从网络上加载回来,并且一次请求太多的图片会导致所有图片都来不及加载。需要仔细考虑什么时候去检查缓冲当中有无图片数据以及什么时候从网络上抓取图片。我们需要预缓存和抓取列阵。

jiangguo
翻译于 11个月前

0人顶

 翻译的不错哦!

快速队列和慢速队列

我们设置了两个队列,一个串行,一个并行。在屏幕上被迫切要求的图片进入并行队列(fastQueue),可能晚点才需要的图片进入串行队列(slowQueue)。

就UITableView的实现而言,这意味着在屏幕上的表格单元从fastQueue获取图片, 每个关闭的屏幕行的图片从slowQueue预加载。

地狱星星
翻译于 1年前

0人顶

 翻译的不错哦!

现在不需要处理图片

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

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

slowGetImageForURL:这个方法将图片添加到slowQueue这个队列当中,允许它们在不阻塞网络通信的前提下被一张一张的取出来。

thenDo:这个代码块在这里是没有被实现,是因为我们目前还不需要对图片做任何事情。所有我们需要做的就是确保它们在本地磁盘缓存当中,并且随时准备在屏幕上滑动表格时来使用。

jiangguo
翻译于 11个月前

1人顶

 翻译的不错哦!

现在就要处理图片

显示在屏幕上的表格希望立即显示它们的图片,所以在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队列中,从而避免重复请求。

jiangguo
翻译于 11个月前

0人顶

 翻译的不错哦!

一直异步

等等,getImageForURL:不是一个异步方法吗?如果你明知道图片已经在缓存中,但是却不想在主线程上立即使用它吗?直觉告诉你那是错误的。

从磁盘上加载图片太费资源,同样解压图片也会费很多资源。可以在滑动的过程当中进行配置和添加表格,这最后一件你想在滑动表格时做的事是很危险地,因为它会阻塞主线程,会有卡顿的现象出现。

使用getImageForURL:可以让磁盘加载的动作脱离主线程,于是当thenDo:这个用于收尾工作的代码块执行的时候它已经有了一个UIImage实例,从而不会有滑动卡顿的危险。如果图片已经存在于本地缓存当中,用于收尾工作的代码块会在下一次运行周期执行,并且用户不会注意到两者之间的差别。他们会注意到的是滑动不会卡顿了。

jiangguo
翻译于 11个月前

0人顶

 翻译的不错哦!

现在,不需要你快速执行

如果用户很快的滑动表格到底部,几十或几百个表格单元会出现在屏幕上,并向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中。

jiangguo
翻译于 11个月前

0人顶

 翻译的不错哦!

重点和选择

已经有相当多的iOS图片缓存库。它们中一些库只针对某些应用场景,一些库提供了不同场景一定的可扩展性。我们的库即没有专门针对某些应用场景,也没有太多大而全的特性。针对我们的用户我们有三类基本的重点:

重点 1: 最好的帧率

很多的库都非常专注在这一点上,使用一些高度定制和复杂的方法,尽管基准没有决定性地显示这样有效。我们发现最好的帧率由这些决定:

  1. 将对磁盘的访问(并且几乎其它的所有)脱离主线程。
  2. 使用UIImage的内存缓存来避免不必要的磁盘访问和图片解压。

jiangguo
翻译于 11个月前

0人顶

 翻译的不错哦!

重点 2: 让最最重要的图片优先显示

大多数的库都考虑让队列管理成为别人关心的事。对于我们的应用,这几乎是最重要的点。

让正确的图片在正确的时间显示在屏幕上可以归结为一个简单的问题:“我们现在就需要它显示还是过一会儿?”。那些需要立即显示的图片是并行加载地,而其它所有东西都被添加到串行队列中。所有之前急迫的事但现在不急迫的话就会从fastQueue分到slowQueue中。并且当fastQueue在工作时,slowQueue是处于挂起状态的。

这让那些急需显示的图片可以单独访问网络,同时也确保了一张非急需显示的图片可以在过一会成为一张急需显示的图片,因为它已经存到了缓存当中,随时准备用于显示。

jiangguo
翻译于 11个月前

0人顶

 翻译的不错哦!

重点 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内置的内存缓存,我们努力从一个简单的软件包中得到好的结果。

一些有用的链接

时间: 2024-10-15 13:47:00

一款轻量级的 iOS 图像缓存的相关文章

iOS图片缓存库基准对比

原文:iOS image caching. Libraries benchmark (SDWebImage vs FastImageCache),译者夜微眠(github地址),校对蓝魂(博客).Cocoa(博客).1.引言 过 去的几年里,iOS应用在视觉方面越来越吸引人.图像展示是其中很关键的部分,因为大部分图像展示都需要下载并且渲染.大部分开发者都要使用图像填充表格 视图(table views) 或者 集合视图(collection views) .下载图片消耗一些资源(如蜂窝数据.电池

iOS 通用缓存:HanekeSwift

iOS 通用缓存:HanekeSwift Haneke 是个采用 Swift 编写的轻量级 iOS 通用缓存.示例: 初始化一个数据缓存: let cache = Cache<NSData>("my-files") Haneke 同时包括一个零配置的图片缓存,可以自动缩放. 示例: imageView.hnk_setImageFromURL(url) 它的设计是超简单易用.这里是你如何初始化一个JSON缓存和从URL获取JSON对象: let cache = Cache&l

iOS网络图片缓存SDWebImage

Web image(网络图像) 该库提供了一个支持来自Web的远程图像的UIImageView类别 它提供了: 添加网络图像和缓存管理到Cocoa Touch framework的UIImageView类别 异步图像下载 An asynchronous memory + disk image caching with automatic cache expiration handling 支持GIF动画 支持WebP格式 后台图像解压 保证相同的url不会下载多次 保证伪造的URL不会尝试一遍又

iOS网络缓存扫盲篇--使用两行代码就能完成80%的缓存需求

iOS网络缓存扫盲篇 --使用两行代码就能完成80%的缓存需求 下篇预告:使用80%的代码来完成剩下的20%的缓存需求 .敬请 star (右上角)持续关注. 目录 当我们在谈论缓存的时候,我们在谈论什么? GET网络请求缓存 80%的缓存需求:两行代码就可满足 控制缓存的有效性 文件缓存:借助ETag或Last-Modified判断文件缓存是否有效 Last-Modified ETag 总结 一般数据类型借助 Last-Modified 与 ETag 进行缓存 剩下20%的网络缓存需求--真的

h.264参考图像列表、解码图像缓存

1.参考图像列表(reference picture list) 一般来说,h.264会把需要编码的图像分为三种类型:I.P.B,其中的B.P类型的图像由于采用了帧间编码的这种编码方式,而帧间编码又是以参考图像为基础进行的,因此需要有个参考图像列表来管理之前生成的参考图像,方便用于对当前图像进行编码. 2.解码图像缓存(decoded picture buffer) 随着图像编码的进行,(解码阶段)会不断有新的图像生成(重建图像),已解码图像会被放到解码图像缓存区中(或直接输出,这个在下面DPB

iOS清理缓存的几种方法

iOS清理缓存的几种方法,有需要的朋友可以参考下: 1.计算文件大小: - (long long) fileSizeAtPath:(NSString*) filePath{ NSFileManager* manager = [NSFileManager defaultManager]; if ([manager fileExistsAtPath:filePath]){ return [[manager attributesOfItemAtPath:filePath error:nil] file

IOS 区分缓存 内存 物理存储 逻辑存储

1. 存储器分为内部存储器(内存)和外部存储器(外存). ①内存 内存是电脑内部临时存放数据的地方,供CPU直接读取,存放在其中的数据要靠电来维持,一旦断电就会丢失.因此,在操作电脑时,应及时地将需要保存的信息进行保存. 内存的特点是:容量小,速度极快,临时存放数据. ②外存 外存包括软盘.硬盘和光盘,存放在其中的数据靠磁来维持,因此可永久保存数据. 外存的特点:容量很大,速度较慢,可永久保存数据. 2. 物理卷Physical Volume,称为PV:指物理上硬盘,一个硬盘就是一个PV逻辑卷组

Viewer 是一款强大的 jQuery 图像浏览插件。

Viewer 是一款强大的 jQuery 图像浏览插件. 主要功能: 支持选项 支持方法 支持事件 支持触摸 支持移动 支持缩放 支持旋转 支持键盘 跨浏览器支持 链接: viewer的官方演示,及github上的开源代码. 使用方法: 1.引入css和js <link rel="stylesheet" href="css/viewer.min.css"> <script src="js/viewer.min.js">&l

iOS之缓存清理

作为一个开发者,对于缓存的清理也是理所应当的需要的.这次就简单的谈一下iOS中对于缓存的清理方法. 我们清理缓存通常是在这三种方式下进行的: (1)项目中的清理缓存按钮 (2)点击退出app按钮时清理缓存 (3)手动杀死进程  (说明:我们使用苹果手机时,大部分人并不喜欢每次都去点击退出app按钮.所以客户就有了在我们手动杀死进程时,对app进行缓存清理的要求) 接下来我们就从这三种方面来分析iOS的清理缓存. 我们知道iOS应用是在沙箱(sandbox)中的,在文件读写权限上受到限制,只能在几