iOS开发网络多线程之多图下载
一. 多线程中多图片下载
头像通过网络下载得到
效果图如下:
二. 设计思路
利用tableView实现多行数据的现实,图标通过网络下载很耗时,需要在子线程中执行.
cell中的ImageView的设置:
1. 首先到图片缓存池中取(定义一个存放图片的的字典属性),如果有直接设置;
2. 如果图片缓存池没有,再到沙盒缓存cache中查看是否存在,如果有直接设置,并把沙盒中的图片写入到图片缓存池中
3. 如果沙盒cache中也没有,就需要开线程下载;
4. 首先判断当前图片是否有任务在下载(定义一个存放任务的字典属性);
5. 如何没有当前没有任务在下载,就开启一个子线程进行数据下载
6. 下载得到一个图片
6.1 这时需要优化,考虑到图片路径不对或者网络比较差,下载图片失败,得到的图片为空,这时需要判断如果为空就直接return,并把此任务从缓存池中移除
7. 下载的图片写入到图片缓存池中
8. 下载的图片同时写入到沙盒中
9. 在主线程中刷新数据
10. 将操作添加到任务缓存池中
11. 队列中添加操作
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID = @"APP";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
LDApp *app = self.apps[indexPath.row];
cell.textLabel.text = app.name;
cell.detailTextLabel.text = app.download;
/*
1.先到缓存中查看有没有图片,判断如有直接设置
2.如果没有进入沙盒中查看是否有icon中的后缀图片,如有直接取出设置,并写入到缓存中
3.如果没有则下载,则查看队列中是否有此下载任务,如果没有就下载完成之后设置并写入到缓存中
*/
// 1.从图片缓存池中取出图片
UIImage *image = self.cacheDict[app.icon];
if (image) {
cell.imageView.image = image;
NSLog(@"从缓存池中加载图片-%zd", indexPath.row);
} else {
// 获取沙盒缓存路径
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
// 截取app名称字符串
NSString *appName = [app.icon lastPathComponent];
// 拼接路径
NSString *appCachePath = [cachePath stringByAppendingPathComponent:appName];
// 加载沙盒路径图片
NSData *data = [NSData dataWithContentsOfFile:appCachePath];
// 判断沙盒路径图片是否存在
if (data) { // 存在
NSLog(@"从沙盒中加载图片-%zd", indexPath.row);
// 直接设置
cell.imageView.image = [UIImage imageWithData:data];
// 写入缓存中
[self.cacheDict setObject:cell.imageView.image forKey:app.icon];
} else { // 沙盒不存在,进行下载
// 设置一个占位图
cell.imageView.image = [UIImage imageNamed:@"t012fea7312194537c2"];
// 判断任务缓存池中是否存在下载此app图片的任务
NSBlockOperation *operation = self.operationDict[app.icon];
if (operation == nil) { // 任务缓存池中没有此任务才进行下载
// 封装任务
operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下载图片-%zd", indexPath.row);
// 获取图片URL
NSURL *url = [NSURL URLWithString:app.icon];
// 加载二进制
NSData *data = [NSData dataWithContentsOfURL:url];
// 将二进制转为图片
UIImage *image = [UIImage imageWithData:data];
// 加载的图片路径不正确或者网速慢下载的图片为空即为下载失败,直接return
if (image == nil) {
// 将任务移除,如果不移除下次就不能进入进行下载,因为当前操作在任务缓存池中
[self.operationDict removeObjectForKey:app.icon];
return;
}
// 将图片加入到图片缓存池中
self.cacheDict[app.icon] = image;
// 将图片写入到沙盒中
[data writeToFile:appCachePath atomically:YES];
// 刷新UI
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
//cell.imageView.image = image;
// 局部刷新
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
// 下载完成之后将任务移除任务池
[self.operationDict removeObjectForKey:app.icon];
}];
}];
// 任务加入到缓存池中
self.operationDict[app.icon] = operation;
[self.queue addOperation:operation];
}
}
}
return cell;
}
三.第三方框架(SDWebImage)
1. 多图下载
第一个参数: 图片的URL路径
第二个参数: 占位图片
// 第三方框架下载多图
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:app.icon] placeholderImage:[UIImage imageNamed:@"t012fea7312194537c2"]];
2. 内存告警清除缓存
清除缓存数据,在applictionDelegate中执行缓存清除
引入"SDWebImageManager.h"头文件
在-(void)applicationDidReceiveMemoryWarning:(UIApplication *)application方法中进行对缓存数据清除
获取图片管理单例执行cancelAll方法进行缓存清除
cancelAll方法内部已经实现了clearDisk方法
#import "AppDelegate.h"
#import "SDWebImageManager.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
-(void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
//当发生内存警告的时候如何处理
//1.取消当前正在下载的所有操作
[[SDWebImageManager sharedManager] cancelAll];
//2.图片缓存处理
/*
kDefaultCacheMaxCacheAge:默认缓存周期是一周
maxCacheSize:
cleanDisk:找到缓存文件,先删除过期缓存,统计当前缓存文件的大小(currentSzie),如果发现大于最大缓存数量(currentSzie>maxCacheSize),那么会继续删除,按照缓存文件产生的事件顺序,从远到进删除,直到小于为止
clearDisk:直接删除,然后创建新的文件夹
*/
//内部已经实现了
// [[SDWebImageManager sharedManager].imageCache clearDisk];
}
@end