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

第03天多线程网络:(04):多图下载程序内存警告补充

2017-04-20 00:00 295 查看
#####一、多图下载程序内存警告补充

>>> 当收到内存警告的时候 进行内存清理
- (void)didReceiveMemoryWarning
{
[self.dict_images removeAllObjects];
[self.queue cancelAllOperations]; // 如果正在下载的话,那么就取消下载
}


code
LYHAppModel

>>>.h
#import <Foundation/Foundation.h>

@interface LYHAppModel : NSObject

/** app的名称 */
@property(nonatomic, strong) NSString *name;

/** app的图标 */
@property(nonatomic, strong) NSString *icon;

/** app的下载量 */
@property(nonatomic, strong) NSString *download;

// 提供一个方法 用于 字典转模型
+ (instancetype)LYHAppModelWithDict:(NSDictionary *)dict;

@end
>>>.m
#import "LYHAppModel.h"

@implementation LYHAppModel
+ (instancetype)LYHAppModelWithDict:(NSDictionary *)dict
{
LYHAppModel *model = [[LYHAppModel alloc]init];

#pragma  字典转模型 几种方式
#pragma mark 1.一个一个转
//model.name = dict["name"];
#pragma mark 2.KVC
[model setValuesForKeysWithDictionary:dict];

return model;
}
@end

VC

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

@interface ViewController ()

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

@property(nonatomic, strong) NSArray *dataA;
/** 内存缓存 */
// 每下载完一张图片 要保存起来
@property(nonatomic, strong) NSMutableDictionary *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;
}

- (NSMutableDictionary *)dict_images
{
if (_dict_images == nil) {
_dict_images = [NSMutableDictionary dictionary];
}
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;
}

// http://p16.qhimg.com/dr/48_48_/t0125e8d438ae9d2fbb.png (图1正确连接)
// http://p16.qhimg.com/dr/48_48_/t0125e8d438ae9d2fb.png (错误连接 正在使用)

/*
1.UI很不流畅 (因为放到主线程里面)  ---> 开启子线程下载图片
2.图片被重复下载  ---> 先把之前已经下载的图片保存起来(字典)
内存缓存 ---> 磁盘缓存(保存到沙盒里面)
3.图片不会刷新(解决)
4.图片重复下载(图片下载需要时间,当图片还未完全下载之前,又要重新显示该图片)
图片的下载操作 添加两到三次 --->[添加操作缓存]
5.数据错乱 --->(设置占位图片)
*/
- (void)didReceiveMemoryWarning
{
[self.dict_images removeAllObjects];
[self.queue cancelAllOperations]; // 如果正在下载的话,那么就取消下载
}
@end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Objective-C 多线程