• 【iOS系列】-多图片多线程异步下载


    多图片多线程异步下载


    开发中非常常用的就是就是图片下载,我们常用的就是SDWebImage,但是作为开发人员,不仅要能会用,还要知道其原理。本文就会介绍多图下载的实现。

    本文中的示例Demno地址,下载后项目位于iOS_Demo/09-多图片多线程下载

    1 - 问题

    开篇我就先将多图下载过程中出现的问题摆出来,让我们能够一一克服

    1:下载过程要放到子线程中,否则会导致UI线程卡顿
    2:图片会重复下载,我们不仅要把下载完的图片放到内存中,还要把下载队列也缓存起来,否则可能图片没有下载完,会多次创建下载队列
    3:沙盒缓存,放到哪里,根据下面对沙盒文件的介绍我们需要把图片放到Library/Caches目录下。

    Document : iTunes会备份
    Library : 
            1:Caches:缓存文件,不会清除
            2:Preferences:偏好设置,保存账号信息
    tmp :临时路径,随时会被删除,临时的不是重要的数据
    

    下载流程图

    明白了问题后,我们需要制定战略(画流程图),这样根据流程图,下载过程就更为清晰明了。

    根据流程图一些坑,我们就可以完美的避免掉了。这样写程序也更有章法。

    2 - 开始下载图片

    根据前面的介绍,我们需要有两个缓存对象:

    1. 图片data的内存缓存
    2. 下载队列的缓存

    我们可以使用NSMutableDictionary进行缓存,

    这里我们假设两个缓存对象分别是:

    /** 内存中图片的缓存字典 */
    @property (nonatomic,strong)NSMutableDictionary * memoryImages;
     
    /** 下载操作的字典 */
    @property (nonatomic,strong)NSMutableDictionary * operations;
    

    2.1 内存缓存中取值

    所以下载前,我们先要到内存中取值

       NSData *imageData = [self.memoryImages objectForKey:url];
    

    如果imageData对象存在,我们就直接设置到Cell上。

    2.2 内存缓存中没有,我们到沙盒中取值

    内存缓存中不存在时我们到沙盒中进行查看:

            NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject;
        //获取图片名字,图片名称不能包含URL,
        NSString *fileName = [url lastPathComponent];
        NSString *filePaPath  = [path stringByAppendingPathComponent:fileName];
    
        //内存中没有图片的缓存 -- 从沙盒中取出
        NSData *imageData = [NSData dataWithContentsOfFile:filePaPath];
    

    如果图片存在,我们需要把图片设置到Cell上,并且放一份到内存缓存中

    //沙盒中取出后,放一份到内存缓存中
    [self.memoryImages setObject:imageData forKey:url];
    

    这样下次就不用频繁访问沙盒了。

    2.2 内存缓存中没有,沙盒中也没有,我们需要判断下载队列是否已经存在

    如果网速慢一些,并且Cell上下滑动的频率快一些的话,假如第一次第5行的Cell显示的时候,内存缓存中没有,沙盒中也没有,这时我们创建了下载对象,然后这行Cell被滑出屏幕,再次进来的时候图片还是没有下载完毕,经过判断内存缓存中没有,沙盒中也没有,我们如果再次创建下载对象的话,就会重复下载图片了,所以我们要把下载队列也进行缓存,当内存缓存中没有,沙盒中也没有时,我们先判断下载队列中是否已经存在了。

    这里使用的是NSBlockOperation
    NSBlockOperation *doo = [self.operations objectForKey:url];

    2.2 内存缓存中没有,沙盒中也没有,下载队列也没有

    这时我们就需要创建下载对象进行下载了。

    首先我们先可以设置一个占位图,这样的显示更为友好一下。

     NSBlockOperation *downO = [NSBlockOperation blockOperationWithBlock:^{
                    NSURL *uurl = [NSURL URLWithString:url];
                    
                    NSURLSession *session = [NSURLSession sharedSession];
                    NSURLSessionDataTask *down = [session  dataTaskWithURL:uurl completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                    //图片的下载过程    
                     
                    }];
                    
                    [down resume];
                }];
    

    同时加入下载队列

      //下载对象加入队列中
     [self.operations setObject:downO forKey:url];
     [self.queue addOperation:downO];
    

    图片下载完毕后,我们需要

    //把图片data存入内存中
    [self.memoryImages setObject:data forKey:url];
    
    //同时写入沙盒中,永久缓存
    [data writeToFile:filePaPath atomically:YES];
    

    同时在主线程中更新UI

     [[NSOperationQueue mainQueue] addOperationWithBlock:^{
       
     UIImage *image = [UIImage imageWithData:data];
     cell.iconView.image = image;
     [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    }];
    

    这样完整的图片下载过程就好了。

  • 相关阅读:
    使用循环计算斐波那契数列
    java 面向过程实现万年历
    学习js回调函数
    序列化和反序列化
    SQL语句增加字段、修改字段、修改类型、修改默认值
    使用SQL语句查询日期(当月天数,当月第一天,当月最后一天,本年最后一天,当月第一个星期) 日期转字符串
    RGB颜色表
    String 与StringBuilder有什么区别
    C# byte数组与Image的相互转换
    CentOS 7 MySQL、Tomcat、Zookeeper设置开机自启
  • 原文地址:https://www.cnblogs.com/fengtengfei/p/6714745.html
Copyright © 2020-2023  润新知