iOS教程:详解iOS多图下载的缓存机制
ios教程,ios的干货一直来不及给大家分享,小编也是一直在忙啊!今天给大家献上ios:详解iOS多图下载的缓存机制
1. 需求点是什么?
这里所说的多图下载,就是要在tableview的每一个cell里显示一张图片,而且这些图片都需要从网上下载。
2. 容易遇到的问题
如果不知道或不使用异步操作和缓存机制,那么写出来的代码很可能会是这样:
cell.textLabel.text = app.name;
cell.detailTextLabel.text = app.download;NSData *p_w_picpathData = [NSData dataWithContentsOfURL:app.url];
cell.p_w_picpathView.p_w_picpath = [UIImage p_w_picpathWithData:p_w_picpathData];
这样写有什么后果呢?
后果1:不可避免的卡顿(因为没有异步下载操作)
dataWithContentsOfURL:是耗时操作,将其放在主线程会造成卡顿。如果图片很多,图片很大,而且网络情况不好的话肯定会卡出翔!
后果2:同一图片重复下载,耗费流量和系统开销(因为没有建立缓存机制)
由于没有缓存机制,即使下载完成并显示了当前cell的图片,但是当该cell再一次需要显示的时候还是会下载它所对应的图片:耗费了下载流量,而且还导致重复操作。
很显然,要达到Tableview滚动的如丝滑般的享受必须二者兼得才可以,具体怎么做呢?
3. 解决方案
1.先看一下解决方案的流程图
要想快速看懂此图,需要先了解该流程所需的所有数据源:
1. 图片的URL:因为每张图片对应的URL都是唯一的,所以我们可以通过它来建立图片缓存和下载操作的缓存的键,以及拼接沙盒缓存的路径字符串。
2. 图片缓存(字典):存放于内存中;键为图片的URL,值为UIImage对象。作用:读取速度快,直接使用UIImage对象。
3. 下载操作缓存(字典):存放与内存中,键为图片的URL,值为NSBlockOperation对象。作用:用来避免对于同一张图片还要开启多个下载线程。
4. 沙盒缓存(文件路径对应NSData):存放于磁盘中,位于Cache文件夹内,路径为“Cache/图片URL的最后的部分”,值为NSData对象(将UIImage转化为NSData才能写入磁盘里)。作用:程序断网,再次启动也可以直接在磁盘中拿到图片。
2. 再看一下解决方案的代码
2.1图片缓存,下载操作缓存,沙盒缓存路径
/**
* 存放所有下载完的图片
*/@property (nonatomic, strong) NSMutableDictionary *p_w_picpaths;/**
* 存放所有的下载操作(key是url,value是operation对象)
*/@property (nonatomic, strong) NSMutableDictionary *operations;/**
* 拼接Cache文件夹的路径与url最后的部分,合并成唯一约定好的缓存路径
*/#define CachedImageFile(url) [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[url lastPathComponent]]
2.2 图片下载之前的查询缓存部分:
//先从p_w_picpaths缓存中取出图片url对应的UIImage
UIImage *p_w_picpath = self.p_w_picpaths[app.icon]; if (p_w_picpath) { //存在:说明图片已经下载成功,并缓存成功)
cell.p_w_picpathView.p_w_picpath = p_w_picpath;
} else { // 不存在:说明图片并未下载成功过,或者成功下载但是在p_w_picpaths里缓存失败,需要在沙盒里寻找对于的图片
// 获得url对于的沙盒缓存路径
NSString *file = CachedImageFile(app.icon); // 先从沙盒中取出图片
NSData *data = [NSData dataWithContentsOfFile:file]; if (data) { //data不为空,说明沙盒中存在这个文件
cell.p_w_picpathView.p_w_picpath = [UIImage p_w_picpathWithData:data];
} else {// 反之沙盒中不存在这个文件
// 在下载之前显示占位图片
cell.p_w_picpathView.p_w_picpath = [UIImage p_w_picpathNamed:@"placeholder"];// 下载图片
[self download:app.icon indexPath:indexPath];
}
}
2.3 图片的下载部分:
/**
* 下载图片
* @param p_w_picpathUrl 图片的url
*/- (void)download:(NSString *)p_w_picpathUrl indexPath:(NSIndexPath *)indexPath
{ // 取出当前图片url对应的下载操作(operation对象)
NSBlockOperation *operation = self.operations[p_w_picpathUrl]; if (operation) return; // 创建操作,下载图片
__weak typeof(self) appsVc = self;
operation = [NSBlockOperation blockOperationWithBlock:^{ NSURL *url = [NSURL URLWithString:p_w_picpathUrl]; NSData *data = [NSData dataWithContentsOfURL:url];// 下载
UIImage *p_w_picpath = [UIImage p_w_picpathWithData:data]; // NSData -> UIImage
// 回到主线程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{ if (p_w_picpath) { // 如果存在图片(下载完成),存放图片到图片缓存字典 中
appsVc.p_w_picpaths[p_w_picpathUrl] = p_w_picpath; //将图片存入沙盒中
//1. 先将图片转化为NSData
NSData *data = UIImagePNGRepresentation (p_w_picpath); //2. 再生成缓存路径
[data writeToFile:CachedImageFile(p_w_picpathUrl) atomically:YES];
} // 从字典中移除下载操作 (保证下载失败后, 能重新下载)
[appsVc.operations removeObjectForKey:p_w_picpathUrl]; // 刷新当前表格,减少系统开销
[appsVc.tableView reloadRowsAtIndexPaths:@ [indexPath] withRowAnimation:UITableViewRowAnimationNone];
}];
}]; // 添加下载操作到队列中
[self.queue addOperation:operation]; // 将当前下载操作添加到下载操作缓存中 (为了解决重复下载)
self.operations[p_w_picpathUrl] = operation;
}
3. 有哪些点是值得注意的?
要说值得注意的地方,还是离不开对于缓存内容的添加和删除操作。
3.1 关于图片缓存:
很简单,成功下载,拿到了图片,就将图片添加到图片缓存中;下载失败,什么都不做,反正没有图。在这种机制下,就没有删除缓存里某个图片项的情况,因为图片缓存永远不会出现重复添加多个相同图片的情况,缓存中只要有一张对应的图,就直接拿去用了,不会去再下载了。
3.2 关于沙盒缓存:
同样地,对于沙盒缓存也是一个道理:有图就将其转化为NSData,写入磁盘,并对应唯一的路径,没有图就不写。所以即使是要下载相同的图片,因为当前url对应的沙盒路径已经存在文件了,所以直接拿就可以了,不会再下载。
但是!
下载操作缓存是不同的!
3.3 关于下载操作缓存
我们需要在下载回调完成后,立即将当前的下载操作从下载操作缓存中删去!
因为要避免下载失败后,无法再次下载的情况的发生!
为什么呢?
注意一下将下载操作加入到下载操作缓存的时机:
是在下载开始的那一刻而不是下载成功的那一刻!
如果在下载开始的那一刻加入到缓存中的话,这个缓存信息就包括两个情况:下载成功和下载失败:
如果未来下载成功了,那么我们就不会来到判断当前下载操作是否在下载操作缓存这一步,在这之前直接就可以拿图去用了,下载操作是否存在下载操作缓存里并没有什么影响。
但是!如果未来下载失败了,那就肯定不会有对应的图片缓存和沙盒缓存,也就肯定会来到判断当前的下载操作是否在下载操作缓存里这一步。不幸的是,因为没有被删去,它是存在的。存在的话就不做任何其他操作,放任自流,导致曾经下载失败的图片永远不会再次下载。
忘了那段代码了么?回看一下代码(看我多好):
NSBlockOperation *operation = self.operations[p_w_picpathUrl]; if (operation) return;//转身就走,毫不留情
因此,无论下载成功或是失败,在图片下载的回调里都要将当前的下载操作从下载操作队列中移走:用来保证如果下载失败了,就可以重新开启对应的下载
操作进行下载,逻辑上更加严谨。
4. 最后的话
异步+缓存这两个机制双剑合璧的话会对程序新能带来很大的改观。这应该app开发进阶的必经之路。
小码哥讲述的这套流程还算比较完整的了,更重要的还是学习其中的思想:
将缓存分级:内存缓存,沙盒缓存,下载操作缓存。
而且还要经常使用二分法,将我们的逻辑考虑得滴水不漏。
如果我们没有认识到将下载操作添加到下载操作缓存的时机是包含下载成功和下载失败两个情况,那么就不会考虑到即时要将下载操作从下载操作缓存中删去的操作,很容易引起bug。所以在以后的开发中,成功和失败两个情况都要考虑进去,也就是说有if一定要有else!
转载于:https://blog.51cto.com/12094558/1858084
iOS教程:详解iOS多图下载的缓存机制相关推荐
- iOS无处不在详解iOS集成第三方登录(SSO授权登录无需密码)
链接地址:http://www.it165.net/pro/html/201408/18884.html 1.前言 不多说,第三登录无处不在!必备技能,今天以新浪微博为例. 这是上次写的iOS第三方社 ...
- IOS 七种手势详解(动图+Demo下载)
原创Blog,转载请注明出处 blog.csdn.net/hello_hwc 欢迎关注我的博客专栏,这个关于IOS SDK的专栏我会持续更新 IOS SDK详解 前言: 触摸是交互的核心,而手 ...
- iOS疯狂详解之开源库
youtube下载神器:https://github.com/rg3/youtube-dl vim插件:https://github.com/Valloric/YouCompleteMe vim插件配 ...
- Xamarin iOS教程之申请付费开发者账号下载证书
Xamarin iOS教程之申请付费开发者账号下载证书 Xamarin iOS使用真机测试应用程序 在讲解iOS Simulator时,已经提到了虽然iOS Simulator可以模仿真实的设备,但是 ...
- iOS绘图详解-多种绘图方式、裁剪、滤镜、移动、CTM
iOS绘图详解 摘要: Core Graphics Framework是一套基于C的API框架,使用了Quartz作为绘图引擎.它提供了低级别.轻量级.高保真度的2D渲染.该框架可以用于基于路径的 绘 ...
- iOS多线程详解:实践篇
iOS多线程实践中,常用的就是子线程执行耗时操作,然后回到主线程刷新UI.在iOS中每个进程启动后都会建立一个主线程(UI线程),这个线程是其他线程的父线程.由于在iOS中除了主线程,其他子线程是独立 ...
- [iOS] 国际化详解
PS:修改设备系统语言方法 设置 -> 通用 -> 语言与地区 -> iPhone 语言 Settings -> General -> Language & Re ...
- Windows系统下nodejs、npm、express的下载和安装教程详解
这篇文章主要介绍了Windows系统下nodejs.npm.express的下载和安装教程详解,非常不错,具有参考借鉴价值,需要的朋友可以参考下 1. node.js下载 首先进入http://nod ...
- 深拷贝与浅拷贝(mutableCopy与Copy)详解 iOS
深拷贝与浅拷贝(mutableCopy与Copy)详解 iOS ios中并不是所有的对象都支持copy,mutableCopy,遵守NSCopying 协议的类可以发送copy消息,遵守NSMutab ...
最新文章
- 挑灯熬夜看《Build 2015 Keynote》图文笔记
- mysql之分页_MySQL之分页查询(DQL)
- verilog将像素数据写入txt_FPGA仿真必备(1)——Matlab生成.mif文件/.txt文件
- 【BZOJ4561】[JLoi2016]圆的异或并
- 【NOIP初赛】【Luogu1787】普及组2013(洛谷初赛题提交水AC方法了解一下)
- android 横竖屏切换时候activity的生命周期,横竖屏切换时候Activity的生命周期
- python抖音涨粉代码_抖音最火表白代码
- pdftomusic pro(音乐谱曲软件) v1.0.4
- 【HTTP协议】HTTP协议初体验,深入浅出网络协议
- 5G版聚合路由器加速释放5G潜能
- 用Visio画软件(模块)功能图
- easyui datagrid deleteRow(删除行)的BUG或者updateRow值更新了不展示问题
- 江苏科技大学计算机学院院长高尚,江苏科技大学计算机科学与工程学院导师介绍...
- 三角定位法java代码_GitHub - megagao/IndoorPos: 这是一个采用蓝牙4.0--iBeacon技术的室内定位服务端程序。...
- 树莓派4B安装官方64位桌面系统
- MySQL环境变量的配置(三)(Windows 11)
- QQ春节红包活动如何应对10亿级流量?看看大佬的复盘总结
- construct2制作飞机大战游戏
- 判断浏览器是pc端还是手机端
- 围绕企业服务总线的测试解决方案及测试场景解析
热门文章
- pip is configured with locations that require TLS/SSL, however the ssl module in Python is not avail
- Python PIL(图像处理库)使用方法
- Linux中的.bash_ 文件的详细说明
- 同步异步 阻塞 非阻塞 异步调用 线程队列 协程
- Permutation(构造+思维)
- 第29月第14天 evpp
- 01_13_JSP编译指令
- android 隐藏系统键盘
- [转]如何完美应对面试
- “左手5G右手AI”,任正非推崇的王喜文在华为这样说