效果图


常见问题及解决方法


  • 图片重复下载

    • 将内存保存在内存或沙盒中。
  • 若下载的图片量较大,则会出现UI界面不流畅的现象

    • 在子线程中执行下载操作,然后回到主线程成中进行UI界面的刷新。
  • 由于cell的循环利用造成的图片显示错乱问题

    • 指定刷新表格的indexPath行。
  • subTitle类型的cell,无法显示图片

    • subtitle类型的cell中的imageView只有在第一次返回cell时设置图片,否则图片将不能显示(刷新表格也不行)。可以通过设置占位图片的方式来解决此问题。

思维导图


具体实现


  • 其核心代码主要在tableView的返回创建cell的代理方法中,所以以下主要对该方法的实现进行解析

  • 主要流程

    • 设置模型类,包含以下属性

      /**图片*/
      @property (nonatomic, strong) NSString *icon;
      /**名字*/
      @property (nonatomic, strong) NSString *name;
      /**下载量*/
      @property (nonatomic, strong) NSString *download;
    • 需要用到的成员属性

      /**模型数组,用来存放每个cell的数据模型*/
      @property (nonatomic, strong) NSArray *apps;
      /**操作队列,操作只有添加到队列才有可能并发执行*/
      @property (nonatomic, strong) NSOperationQueue *queue;
      /**用于在内存中缓存图片,部分避免图片被多次下载*/
      @property (nonatomic, strong) NSMutableDictionary *imageCache;
      /**标记当前所有正在执行的操作,避免正在执行的操作被重复执行*/
      @property (nonatomic, strong) NSMutableDictionary *operations;
    • 创建cell的方法的核心代码

      • 从内存缓存中取图片

        //内存中缓存的图片在imagCache数组中
        self.imageCache[app.icon]
      • 从沙盒中取图片

        //获取文件路径
        NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
        //获取文件名
        NSString *filename = [app.icon lastPathComponent];
        //计算出全路径
        NSString *file = [cachePath stringByAppendingPathComponent:filename];
        //加载沙盒中的数据
        NSData *data = [NSData dataWithContentsOfFile:file];
        //判断data中若有数据,否则从网络上下载数据
        if (data)
        {//沙盒中有数据
        UIImage *image = [UIImage imageWithData:data];
        cell.imageView.image = image;
        //存到字典中(即内存)
        self.imageCache[app.icon] = cell.imageView.image;
        }
      • 从网络上下载数据

        //若subTitle类型的cell要显示图片,必须在第一次放回cell时就显示图片(或占位图片)
        cell.imageView.image = [UIImage imageNamed:@"1"];
        //取得操作队列中的操作
        NSOperation *operation = self.operations[app.icon];
        if (operation == nil)
        {//不存在该图片的下载操作
        //创建下载图片操作
        operation = [NSBlockOperation blockOperationWithBlock:^{
        //通过url加载数据
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:app.icon]];
        //数据加载失败
        if (data == nil)
        {
        //移除操作,以便刷新表格时能够再次请求数据
        [self.operations removeObjectForKey:app.icon];
        return ;
        }
        //NSData转换为UIImage
        UIImage *image = [UIImage imageWithData:data];
        //存放到字典中
        self.imageCache[app.icon] = image;
        //线程睡眠,模拟大数据下载
        [NSThread sleepForTimeInterval:1];
        //回主线程显示图片
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        //通过indexPath刷新表格,此时内存缓存中已有图片
        [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
        }];
        //将图片写入沙盒
        [data writeToFile:file atomically:YES];
        //移除操作,保证在刷新表格时可以重新下载没有下载的图片
        [self.operations removeObjectForKey:app.icon];
        }];
        //将操作添加到队列
        [self.queue addOperation:operation];
        //保证图片不被重复下载
        self.operations[app.icon] = operation;

通过第三方框架(SDWebImage)


  • SDWebImage可以大大简化多图下载任务
  • 通过扩展UIImageView的分类,在分类方法中实现多图下载功能,只给外部使用者暴露一个简单地网络接口
  • 包含分类头文件UIImageView+WebCache.h

  • 图片下载功能的实现

    • 方法一

      - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder
      /**
      url:图片的地址
      placeholder:占位图片
      */
    • 方法二

      - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock
      /**
      progressBlock:下载过程中的回调Block,可以在该Block中计算下载进度
      completedBlock:下载完毕的回调方法
      */
 
 

OC - 20.多图下载的更多相关文章

  1. iOS多线程-05-多图下载

    效果图 常见问题及解决方法 图片重复下载 将内存保存在内存或沙盒中. 若下载的图片量较大,则会出现UI界面不流畅的现象 在子线程中执行下载操作,然后回到主线程成中进行UI界面的刷新. 由于cell的循 ...

  2. thinkPHP框架5.0 类图下载

    thinkPHP5.0 类图下载

  3. 详解iOS多图下载的缓存机制

    1. 需求点是什么? 这里所说的多图下载,就是要在tableview的每一个cell里显示一张图片,而且这些图片都需要从网上下载. 2. 容易遇到的问题 如果不知道或不使用异步操作和缓存机制,那么写出 ...

  4. ios开发多线程四:NSOperation多图下载综合案例

    #import "ViewController.h" #import "XMGAPP.h" @interface ViewController () /** t ...

  5. iconfont.cn阿里巴巴矢量图下载字体图标实战

    1.阿里巴巴矢量图网址:www.iconfont.cn 2.然后用新浪微博账号登录 3.输入要查找的图标相应的关键字,回车 4.滑过要找的图标,点击购物车,让图标存储到暂存架中 5.点击暂存架,存储为 ...

  6. JS生成gif动态图下载

    需求:通过动态变化的图生成一个gif图提供下载. 实现方案:1.可通过服务端生成对应gif,然后前端请求下载2.前端自己实现生成gif图片,自行下载 采用方案:前端实现方式,于是在网上找各种相关的几款 ...

  7. 2 万字 + 20张图| 细说 Redis 九种数据类型和应用场景

    作者:小林coding 计算机八股文网(操作系统.计算机网络.计算机组成.MySQL.Redis):https://xiaolincoding.com 大家好,我是小林. 我们都知道 Redis 提供 ...

  8. OC - GCD 队列组 - 下载图片画图

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ [self downloadIma ...

  9. OC 思维导向图

      iOS 扩展思维导向图,如下图所示:

随机推荐

  1. Extjs通过structs2生成树结构

    Extjs为我们提供了强大的树的生成方式,我们不必通过原始的js去生成树形结构.在这里我做了一个简单的树结构生成.代码如下,同时在后台使用了fastjson-1.1.15.jar的jar包生成json ...

  2. Bug in Code

    Coder-Strike 2014 - Finals (online edition, Div. 1) C:http://codeforces.com/problemset/problem/420/C ...

  3. XSHELL和XFTP,亲兄弟啊。

    XSHELL在LINUX和WINDOWS之间传输文件时不力啊.又对FTP不灵活的时候,XFTP就可以出场了. 只要登陆进XSHELL就可以操作了.并且XFTP客户端和命令行可以灵活配置选择. 然后,玩 ...

  4. java.lang.String.indexOf()用法

    java.lang.String.indexOf(char ch) 方法返回字符ch在指定字符串中第一次出现的下标索引位置 如果字符ch在指定的字符串中找不到,则返回-1 示例: import jav ...

  5. bzoj2818

    我们先穷举素数p然后令y>x 这样问题就是求这个gcd(x,y)=p  (1<=x<y=n)不难发现必须y=kp k∈N* 当y=p时,易知个数为φ(1)当y=2p 个数为φ(2), ...

  6. Search Insert Position——LeetCode

    Given a sorted array and a target value, return the index if the target is found. If not, return the ...

  7. ssh技巧

    1. 打通ssh key的简单方法: ssh-copyid 192.168.1.1 2.使用ssh 将Linux主机变成http代理服务器 ssh -NfD 192.168.22.1:10080 12 ...

  8. angularJS 过滤器 表单验证

    过滤器1.filter的作用就是接收一个输入,通过某个规则进行处理,然后返回处理后的结果,主要用于数据的格式化.2.内置过滤器(1)Currency(货币)将一个数值格式化为货币格式,默认为$(2)D ...

  9. [置顶] cocos2d-x 植物大战僵尸(4) 帽子僵尸的产生

         大家早上好,趁着阳光美好的时候,我打算写下博客:今天要说的是僵尸的产生了,这块和太阳因子的产生比较相似,大体上的区别在于僵尸的基类这块:我在考虑是详细的写还是大体的写,本着对自己作业的态度和 ...

  10. oracle存储过程含参数的插入数据

    create or replace procedure proczipcodebyzipinsert(   i_zipcode  in  zipcode.zip%type,   i_city in z ...