iOS学习笔记-123.多线程22——多图下载2_第二种实现方式(三级缓存)

来源:互联网 发布:蓝月传奇光翼升阶数据 编辑:程序博客网 时间:2024/05/24 05:28

  • 多线程22多图下载2_第二种实现方式三级缓存
    • 一分析第一种方式的不足
    • 二三级缓存
      • 1 什么是三级缓存
      • 2 三级缓存的工作原理
    • 三多图下载三级缓存分析
    • 四代码
    • 五图示

多线程22——多图下载2_第二种实现方式(三级缓存)

一、分析第一种方式的不足

iOS学习笔记-122.多线程21——多图下载1_第一种实现方式(不靠谱)

中,我们实现的方式存在严重不足。

  1. 使用了主线程去下载图片,使其UI卡顿

  2. 图片重复下载。

针对上面的问题我们解决方式如下

针对问题1,我们可以使用多线程来下载

针对问题2,我们可以使用三级缓存


二、三级缓存

2.1 什么是三级缓存

三级缓存就是

网络缓存, 不优先加载, 速度慢,浪费流量

本地缓存, 次优先加载, 速度快

内存缓存, 优先加载, 速度最快

2.2 三级缓存的工作原理

  1. 首先从内存中获取我们需要的资源,是否存在。如果存在,那么就是使用资> 源,如果不存在进行步骤2

  2. 从本地(磁盘)中获取我们需要的资源, > 是否存在。如果存在,那么就是使用资源,如果不存在进行步骤3

  3. 从网络中获取我们的资源来使用。


三、多图下载三级缓存分析

流程如图:

这里写图片描述

  1. 根据url我们生成对一个的图片唯一标示符,作为图片的名字。

  2. 从内存中判断我们的图片已经存在了,如果存在直接拿来显示。如果不存在继续步骤3

  3. 从本地(磁盘)中判断图片是否已经存在,如果存在直接拿来显示。如果不存在继续步骤4

  4. 判断我们的操作缓存中,如果存在那么不处理(子线程下载完成以后,会通知到主线程上来),如果不存在,那么添加下载操作到队列中和操作缓存中。

  5. 图片下载好以后,把图片添加到内存和本地缓冲中,把操作从操作缓存中移除。添加实现图片的任务到主线程中。

注意:处理上面,我们应该还要处理内存不足的情况,这个时候,我们移除内存中的图片和操作。


四、代码

////  ViewController.m//  03_UIview86多线程_多图下载////  Created by 杞文明 on 17/9/6.//  Copyright © 2017年 杞文明. All rights reserved.//#import "ViewController.h"#import "QWMAppItem.h"#import "NSString+MD5.h"@interface ViewController ()/** tableView的数据源 */@property (nonatomic, strong) NSArray *apps;/** 内存缓存 */@property (nonatomic, strong) NSMutableDictionary *images;/** 队列 */@property (nonatomic, strong) NSOperationQueue *queue;/** 操作缓存 */@property (nonatomic, strong) NSMutableDictionary *operations;@end@implementation ViewController-(NSArray*)apps{    if(_apps==nil){        //字典数据        NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"apps.plist" ofType:nil]];        //字典数据转模型数据        NSMutableArray *arrM = [NSMutableArray array];        for (NSDictionary *dict in array) {            [arrM addObject:[QWMAppItem appWitdDict:dict]];        }        _apps = arrM;    }    return _apps;}-(NSMutableDictionary*)images{    if(_images==nil){        _images = [NSMutableDictionary dictionary];    }    return _images;}-(NSOperationQueue *)queue{    if(_queue == nil){        _queue = [[NSOperationQueue alloc]init];        //设置最大并发数        _queue.maxConcurrentOperationCount = 5;    }    return _queue;}-(NSMutableDictionary *)operations{    if(_operations == nil){        _operations = [NSMutableDictionary dictionary];    }    return _operations;}/*组数*/-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{    return 1;}/*每组的行数*/-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{    return self.apps.count;}/*每个cell*/-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    static NSString* identifier = @"cell";    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];    //获取数据    QWMAppItem *appItem = self.apps[indexPath.row];    cell.textLabel.text = appItem.name;    cell.detailTextLabel.text = appItem.download;    [self handle2:cell withItem:appItem withIndex:indexPath];//    [self handle1:cell withItem:appItem];    return cell;}/*图片的第二种种处理方式*/-(UITableViewCell*)handle2:(UITableViewCell*)cell withItem:(QWMAppItem*)appItem withIndex:(NSIndexPath*)indexPath{    //1.首先判断内存中是否已经存在,存在直接取    //2.内存中不存在,判断本地是否存在,存在直接取。    //3.本地不存在,判断当前的图片是否已经添加到任务中,如果是,那么不操作    //4.如果没有添加到任务中,那么我们把下载图片的操作添加到任务中    //获取我们图片地址的MD5值作为唯一标识符 MD5+后缀名    NSString *imageID = [NSString stringWithFormat:@"%@.%@",[appItem.icon MD5_32BitLower],[appItem.icon pathExtension]];    UIImage *image = [self.images objectForKey:imageID];    if(image){        //使用内存缓存        cell.imageView.image = image;         NSLog(@"%zd处的图片使用了内存缓存中的图片",indexPath.row);    }else{        //1.获取沙盒的路径        NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];//        NSLog(@"%@",caches);        //2.拼接我们图片的地址        NSString * imageFullPath = [caches stringByAppendingPathComponent:imageID];        //3.获取本地磁盘中的图片数据        NSData *imageData = [NSData dataWithContentsOfFile:imageFullPath];        //4.判断数据是否已经存在,存在说明我们有本地缓存,那么我们直接拿来显示        if (imageData) {            //使用本地缓存            cell.imageView.image = [UIImage imageWithData:imageData];            NSLog(@"%zd处的图片使用了本地缓存中的图片",indexPath.row);        }else{            //都没有,那么我们就需要去网络下载了            //我们获取先去判断一下,我们的这个图片下载任务是否已经在队列中存在,如果有不操作,没有那么我们添加一个下载任务            NSBlockOperation *download = [self.operations objectForKey:imageID];            if(!download){//没有这个任务,那么我们就添加任务                //为了解决滑动时候数据显示错乱,我们现在添加一张图片,用于做默认显示                cell.imageView.image = [UIImage imageNamed:@"image1"];                //创建现在任务                download = [NSBlockOperation blockOperationWithBlock:^{                    //下载                    NSURL *url = [NSURL URLWithString:appItem.icon];                    NSData *imageData = [NSData dataWithContentsOfURL:url];                    UIImage *image = [UIImage imageWithData:imageData];                    //容错处理                    if (image == nil) {                        //如果这个下载有误,那么我们不操作了,并且从操作缓存中移除,为了下一次还能下载                        [self.operations removeObjectForKey:imageID];                        return ;                    }                    //下载好了,现在需要如下操作                    //1.数据添加到内存缓存中                    //2.数据添加到本地中(本地缓存)                    //3.主线程中显示数据                    [self.images setObject:image forKey:imageID];//内存缓存                    [imageData writeToFile:imageFullPath atomically:YES];//本地缓存                    [[NSOperationQueue mainQueue] addOperation:[NSBlockOperation blockOperationWithBlock:^{//主线程显示,就是去刷新这一行                        [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];                    }]];                    //下载已经好了,那么移除图片下载操作                    [self.operations removeObjectForKey:imageID];                }];                //把任务添加到队列中                [self.queue addOperation:download];                //添加任务到操作缓存中,等到下载好了再把它移除                [self.operations setObject:download forKey:imageID];            }        }    }    return cell;}/* 图片的第一种处理方式,存在的问题 1.UI很不流程 ------> 开启子线程下载 2.图片重复下载 ----->先把之前已经下载的图片保存起来(字典) */-(UITableViewCell*)handle1:(UITableViewCell*)cell withItem:(QWMAppItem*)appItem{    NSURL *url = [NSURL URLWithString:appItem.icon];    NSData *data = [NSData dataWithContentsOfURL:url];    UIImage *image = [UIImage imageWithData:data];    cell.imageView.image = image;    return cell;}/*内存警告*/-(void)didReceiveMemoryWarning{    //内存不存的时候删除我们的缓存    [self.operations removeAllObjects];    [self.images removeAllObjects];}@end

五、图示

这里写图片描述

阅读全文
0 0
原创粉丝点击