最近研究了一下UITbleView中异步加载网络图片的问题,iOS应用经常会看到这种界面。
一个tableView上显示一些标题、详情等内容,在加上一张图片。
这里说一下这种思路。

为了防止图片多次下载,我们需要对图片做缓存,缓存分为内存缓存于沙盒缓存,我们当然两种都要实现。
由于tableViewCell是有重用机制的,也就是说,内存中只有当前可见的cell数目的实例,滑动的时候,新显示cell会重用被滑出的cell对象。这样就存在一个问题:

一般情况下在我们会在cellForRow方法里面设置cell的图片数据源,也就是说如果一个cell的imageview对象开启了一个下载任务,这个时候该cell对象发生了重用,新的image数据源会开启另外的一个下载任务,由于他们关联的imageview对象实际上是同一个cell实例的imageview对象,就会发生2个下载任务回调给同一个imageview对象。这个时候就有必要做一些处理,避免回调发生时,错误的image数据源刷新了UI。

所以在我们向下滑动tableview的时候我们需要手动去取消掉下载操作,当用户停止滑动,再去执行下载操作。SDWebImage采用的也是这种策略。

很简单我们只需要监听ScrollView的代理方法(tableview继承自Scrollview)。

/**
* 当用户开始拖拽表格时调用
*/
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
// 暂停下载
[self.queue setSuspended:YES];
} /**
* 当用户停止拖拽表格时调用
*/
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
// 恢复下载
[self.queue setSuspended:NO];
}

而SDWebImage才用的就是这种方式,所以在运行SDWebImage的demo的时候,可以看到,如果快速滑下去,然后又滑回来的话,图片是过了一会才显示出来,这是因为快速滑动的时候,旧数据源的下载任务被取消掉了。
/-------------------------------------------

下面介绍一下具体的思路。
异步下载图片我们用的是NSOperation,并且创建一个全局的queue来管理下载图片的操作。

/**
* 存放所有下载操作的队列
*/
@property (nonatomic,strong) NSOperationQueue* queue;

另外需要两个字典operations、images

/**
* 存放所有的下载操作(url是key,operation对象是value)
*/
@property (nonatomic,strong) NSMutableDictionary* operations;
/**
* 存放所有下载完成的图片,用于内存缓存,同样用Url为key
*/
@property (nonatomic,strong) NSMutableDictionary* images;

在把图片显示到Cell上之前
先判断内存中(images字典中)有没有图片,
如果有,则取出url对应的图片来显示,
如果没有,再去沙盒缓存中查看,当然存到沙盒中都是NSData。
如果沙盒缓存中有,我们取出对应的数据给Cell去显示
如果沙盒中也没有图片,我们先显示占位图片。再创建operation去执行下载操作了。
当然在创建operation之前,我们要判断这个operation操作是否存在
这个时候就用到我们operations这个字典了

//取出当前URL对应的下载操作
NSBlockOperation* operation = self.operations[app.icon];

如果没有下载操作,我们才需要真正的去创建operation执行下载。
创建好下载操作之后应该把该操作存放到全局队列中去异步执行,同时吧操作放入operations字典中记录下来。

//添加操作到队列中
[self.queue addOperation:operation];
//添加到字典中
self.operations[app.icon] = operation;

下载完成之后:
把下载好的图片放到内存中、同时存到沙盒缓存中
下面存放到沙盒中的代码可以定义成宏,具体可以下载后面的demo

if (image) { //防止下载失败为空赋值造成崩溃
vc.images[app.icon] = image; //下载完成的图片存入沙盒中
// UIImage --> NSData --> File(文件)
NSData* ImageData = UIImagePNGRepresentation(image); NSString* CachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString* filePath = [CachesPath stringByAppendingPathComponent:[app.icon lastPathComponent]]; [ImageData writeToFile:filePath atomically:YES];
}

执行完上面的操作之后回到主线程刷新表格,
从operations字典中移除下载操作(防止operations越来越大,同时保证下载失败后,能重新下载)

//刷新当前行的图片数据
self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];

这里我们不用[self.tableView reloadata],因为会刷新整个cell,浪费性能。

当然如果你的下载操作里面需要做的事情很多的时候,可以考虑自定义operation。 由于我这里只是简单的下载小图就没有自定义operation了。注意要自己创建自动释放池。

iOS Cell异步图片加载优化,缓存机制详解的更多相关文章

  1. iOS异步图片加载优化与常用开源库分析

    网络图片显示大体步骤: 1.下载图片: 2.图片处理(裁剪,边框等): 3.写入磁盘: 4.从磁盘读取数据到内核缓冲区: 5.从内核缓冲区复制到用户空间(内存级别拷贝): 6.解压缩为位图(耗cpu较 ...

  2. YYWebImage——iOS异步图片加载框架

    本文转载至 http://www.mobile-open.com/2015/86582.html   YYWebImage 是一个异步图片加载框架 (YYKit 组件之一). 其设计目的是试图替代 S ...

  3. Android高效异步图片加载框架

    概述 Android高效异步图片加载框架:一个高效的异步加载显示的图片加载框架,同时具备图片压缩,缓存机制等特性. 详细 代码下载:http://www.demodashi.com/demo/1214 ...

  4. Android图片加载与缓存开源框架:Android Glide

    <Android图片加载与缓存开源框架:Android Glide> Android Glide是一个开源的图片加载和缓存处理的第三方框架.和Android的Picasso库类似,个人感觉 ...

  5. 浏览器 HTTP 协议缓存机制详解

    最近在准备优化日志请求时遇到了一些令人疑惑的问题,比如为什么响应头里出现了两个 cache control.为什么明明设置了 no cache 却还是发请求,为什么多次访问时有时请求里带了 etag, ...

  6. 浏览器 HTTP 协议缓存机制详解--网络缓存决策机制流程图

    1.缓存的分类 2.浏览器缓存机制详解 2.1 HTML Meta标签控制缓存 2.2 HTTP头信息控制缓存 2.2.1 浏览器请求流程 2.2.2 几个重要概念解释 3.用户行为与缓存 4.Ref ...

  7. nginx平台初识(二) 浏览器 HTTP 协议缓存机制详解

    1.缓存的分类 缓存分为服务端侧(server side,比如 Nginx.Apache)和客户端侧(client side,比如 web browser). 服务端缓存又分为 代理服务器缓存 和 反 ...

  8. PHP缓存机制详解

    一,PHP缓存机制详解 我们可以使用PHP自带的缓存机制来完成页面静态化,但是仅靠PHP自身的缓存机制并不能完美的解决页面静态化,往往需要和其他静态化技术(通常是伪静态技术)结合使用. output ...

  9. 二,PHP缓存机制详解

    一,PHP缓存机制详解 我们可以使用PHP自带的缓存机制来完成页面静态化,但是仅靠PHP自身的缓存机制并不能完美的解决页面静态化,往往需要和其他静态化技术(通常是伪静态技术)结合使用. output ...

随机推荐

  1. 65*24=1560<2175 对数据的统计支撑决策假设 历史数据正确的情况下,去安排今后的任务

    没有达到目标,原因不是时间投入不够,而是不用数据决策,不用数据调度定时脚本 [数据源情况统计]----># 近30天,日生效coin数目SELECT COUNT(DISTINCT coin) A ...

  2. XMU 1608 nc与加法进位 【二分】

    1608: nc与加法进位 Time Limit: 2000 MS  Memory Limit: 128 MBSubmit: 29  Solved: 27[Submit][Status][Web Bo ...

  3. (MySQL里的数据)通过Sqoop Import HDFS 里 和 通过Sqoop Export HDFS 里的数据到(MySQL)(五)

    下面我们结合 HDFS,介绍 Sqoop 从关系型数据库的导入和导出 一.MySQL里的数据通过Sqoop import HDFS 它的功能是将数据从关系型数据库导入 HDFS 中,其流程图如下所示. ...

  4. Ubuntu如何定时清理内存

    Ubuntu如何定时清理内存 1.进入su jiqing@Ubuntu:~$ su 密码: root@Ubuntu:/home/jiqing# 2.创建cleanCache.sh #!/bin/bas ...

  5. 1.ARC下是否有内存溢出等问题 2.@property参数 3.#import和@class的区别

    1.ARC下是否有内存溢出等问题? 答案:必须要担心啊,ARC也不是万能的.答案:必须要担心啊,ARC也不是万能的.这里主要是涉及到集合类的数据类型   比如数组,我们定义了一个可变数组muarr1, ...

  6. 并不对劲的bzoj3214:p3333:[ZJOI2013]丽洁体

    题目大意 有三个由若干个单词组成的字符串\(T,A,B,C(|T|,|A|,|B|,|C|\leq 5*10^4,单词长度\leq5,每个单词出现次数\leq500)\) 求从\(T\)中至少删去多少 ...

  7. 并不对劲的bzoj4560:p3269:[JLOI2016]字符串覆盖

    题目大意 \(T\)(\(T\leq10\))组询问 每组询问给出一个字符串\(A\)(\(|A|\leq10^4\)),\(n\)(\(n\leq4\))个\(A\)的子串\(B_1,B_2,B_3 ...

  8. BZOJ_3172_[Tjoi2013]单词_后缀自动机

    BZOJ_3172_[Tjoi2013]单词_后缀自动机 Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次. ...

  9. lua 与C通过c api传递table

    此文转自http://blog.csdn.net/perfect2011/article/details/19200511(感谢...) 首先了解下c++与lua之间的通信: 假设在一个lua文件中有 ...

  10. Entity Framework Code First 迁移

    Entity Framework CodeFirst数据迁移 http://www.cnblogs.com/aehyok/p/3325459.html Entity Framework Code Fi ...