您的位置:首页 > 理论基础 > 计算机网络

第03天多线程网络:(11):多图下载程序应用NSCache

2017-04-24 00:00 417 查看
#####一、多图下载程序应用NSCache

NSCache 和 NSMutableDictionary 基本相同
NSCache比NSMutableDictionary 多了几个属性
totalCostLimit 总成本 (如果发现存的数据超过总成本,那么会自定回收之前的对象)
countLimit 设置最多可以缓存多少个数据 (如果当前数据大于这个数据 ,那么重新加载)


code
NSCache简单介绍
VC

#import "ViewController.h"
#import "LYHAppModel.h"

@interface ViewController ()

/** 数组源 */
// 如何选择使用 可变还是不可变 是根据需求来说的
// 如果数据是固定的 那么就用 不可变的
// 如果数据是不固定 那么就用 可变的

@property(nonatomic, strong) NSArray *dataA;
/** 内存缓存 */
// 每下载完一张图片 要保存起来
//@property(nonatomic, strong) NSMutableDictionary *dict_images;
@property(nonatomic, strong) NSCache *dict_images;

/** 队列(用来下载任务) */
@property(nonatomic, strong)NSOperationQueue *queue;

/* 图片下载操作缓存 */
@property(nonatomic, strong) NSMutableDictionary *dict_operations;

@end

@implementation ViewController
#pragma mark 懒加载
- (NSMutableDictionary *)dict_operations
{
if (_dict_operations == nil) {
_dict_operations = [NSMutableDictionary dictionary];
}
return _dict_operations;
}

- (NSOperationQueue *)queue
{
if (_queue == nil) {
_queue = [[NSOperationQueue alloc]init];
// 在程序里面 最好只开3~5个队列
// 设置队列并发数
_queue.maxConcurrentOperationCount = 5;
}
return  _queue;
}

- (NSCache *)dict_images
{
if (_dict_images == nil) {
_dict_images = [[NSCache alloc]init];
// 设置最多可以缓存多少个数据
_dict_images.countLimit =  4;
}
return _dict_images;
}

- (NSArray *)dataA
{
if (_dataA == nil) {

// 字典数组
NSArray *arr = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil]];
NSMutableArray *arrM = [NSMutableArray array];
for (NSDictionary *dict in arr) {
[arrM addObject:[LYHAppModel LYHAppModelWithDict:dict]];
}
_dataA = arrM;

}
return _dataA;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}

#pragma mark --- ---
#pragma mark tableViewDataScoure
// 多少组
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}

// 多少行
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.dataA.count;
}

// cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 1.创建cell
static NSString *ID = @"app";
// 2.设置cell数据
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
// 拿到该行cell的数据
LYHAppModel *model = [self.dataA objectAtIndex:indexPath.row];
// 设置数据

cell.textLabel.text = model.name;
cell.detailTextLabel.text = model.download;

//2.4 先去内存缓存中,该图片是否存在,如果存在,那么就直接拿到用,否则去检查磁盘缓存
// 如果有磁盘缓存,那么保存一份到内存,设置图片,否则就直接下载
// 1)没有下载过
// 2)重新打开程序 (先去判断内存缓存有没有,没有再去磁盘缓存里面查找,找到了还需要保存到内存缓存里面)

UIImage *image = [self.dict_images objectForKey:model.icon];
if (image) {
cell.imageView.image = image;
NSLog(@"--%zd的图片使用内存缓存图片",indexPath.row);

}
else
{

NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *fileName = [model.icon lastPathComponent]; // 获取文件的最后节点
NSString *fullPath = [caches stringByAppendingPathComponent:fileName];
//NSLog(@" fullPath %@",fullPath);

// 检查磁盘缓存(是否存在)
NSData *imageData = [NSData dataWithContentsOfFile:fullPath];
// 废除磁盘缓存
imageData = nil;
if (imageData)
{
UIImage *image = [UIImage imageWithData:imageData];
cell.imageView.image = image;
NSLog(@"--%zd的图片使用磁盘缓存图片",indexPath.row);

// 1.把图片保存到内存缓存
[self.dict_images setObject:image forKey:model.icon];
}
else
{
// 不存在
// 检查该图片是否正在下载(如果是 ,那么什么都不做,否则再添加下载操作)
NSBlockOperation *downloadOp = [self.dict_operations objectForKey:model.icon];

if (downloadOp) {
// 下载操作 存在
// 什么都不做
}
else
{
// 先清空cell原来的图片
cell.imageView.image = [UIImage imageNamed:@"lyh165"]; // 占位图片
//            NSOperationQueue *queue = [[NSOperationQueue alloc]init]; // 1.非主队列
downloadOp = [NSBlockOperation blockOperationWithBlock:^{
NSURL *url = [NSURL URLWithString:model.icon];
NSData *imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
//                NSLog(@"---download --%@",[NSThread currentThread]);

#pragma UI刷新的操作
NSLog(@"%zd---下载-- ",indexPath.row);

// 容错处理
// 可能服务器返回的URL不对
if (image == nil) {
// 为了服务器能够改过来,我们还需要处理
// 移除当前的key
[self.dict_operations removeObjectForKey:model.icon];
return ;
}

// 演示网速慢的情况
//                    [NSThread sleepForTimeInterval:2.0];
// 1.把图片保存到内存缓存(演示网速慢的情况 会闪退)
[self.dict_images setObject:image forKey:model.icon];

// 线程之间的通信
[[NSOperationQueue mainQueue]addOperationWithBlock:^{
// [self.tableView reloadData]; 刷新整个tableview
// 刷新某一行
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
cell.imageView.image = image;
//                    NSLog(@"---UI --%@",[NSThread currentThread]);
}];

/*
参数1 : 写到那个位置
参数2 : 表示原子性
*/
[imageData writeToFile:fullPath atomically:YES];

// 图片下载完之后,移除下载操作
[self.dict_operations removeObjectForKey:model.icon];

}]; // 2.封装操作

// 添加操作 到 操作缓存中
[self.dict_operations setObject:downloadOp forKey:model.icon];
// 3.添加操作到队列中
[self.queue addOperation:downloadOp];
}
}

}

return cell;
}

#pragma mark tableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

NSArray *arr = self.dataA;
// 检查缓存数量
for (NSInteger i = 0; i<arr.count; i++) {
LYHAppModel *model = arr[i];

UIImage *img = [self.dict_images objectForKey:model.icon];

if (img) {
NSLog(@"存储图片缓存 %zd",i);

}
}
}

@end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Objective-C 多线程