美文网首页
多线程实现多图片下载

多线程实现多图片下载

作者: by小杰 | 来源:发表于2016-09-20 20:30 被阅读256次

    本文参考: http://www.jb51.net/article/81614.htm
    难点: 如何从网上下载这些图片,下载之后应如何进行存储!
    我们一步一步进行解析,先从单线程(主线程)进行多图片下载我们布局上的文字及图片的地址从plist文件中进行读取.

    数据

    根据结构,我们自定义一个数据模型文件

    DDZApp.h

    #import<Foundation/Foundation.h>
    
    @interface DDZApp : NSObject
    //图标
    @property (nonatomic,strong) NSString *icon;
    
    //名字
    @property (nonatomic,strong) NSString *name;
    
    //下载量
    @property (nonatomic,strong) NSString *download;
    
    + (instancetype)appWithDict:(NSDictionary *)dict;
    
    @end```
    
    **DDZApp.m**
    

    import"DDZApp.h"

    @implementationDDZApp

    • (instancetype)appWithDict:(NSDictionary *)dict {

      DDZApp *app = [[self alloc] init];

      [app setValuesForKeysWithDictionary:dict];

      return app;

    }

    @end```
    以下的都是视图控制器中的代码
    ViewController.m

    @interface ViewController ()
    //所有数据
    @property (nonatomic,strong)NSArray *apps;
    //内存缓存图片
    @property (nonatomic,strong)NSMutableDictionary *imgCache;
    /**所有操作*/
    @property (nonatomic,strong)NSMutableDictionary *operations;
    /**队列对象*/
    @property (nonatomic,strong) NSOperationQueue *queue;
    @end```
    第一个属性用于存储读取plist文件中的内容,设置为属性保存起来,就可以不用重复读取
    第二个属性用于保存从网上下载下来的图片,也是为了不用重复读取
    第三个operations使用来存储下载图片的线程操作的字典,主要作用是防止重复下载
    第四个queue则是使用多线程时用到的队列
    
    

    @implementation ViewController
    //读取数据

    • (NSArray *)apps {
      if (!_apps) {
      //从plist文件中读取数据
      NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"apps.plist" ofType:nil]];
      NSMutableArray *appArray = [NSMutableArray array];
      for (NSDictionary *dict in dictArray) {
      [appArray addObject:[DDZApp appWithDict:dict]];
      }
      _apps = appArray;
      }
      return _apps;
      }
      //缓存图片

    • (NSMutableDictionary *)imgCache {
      if (!_imgCache) {
      //初始化
      _imgCache = [NSMutableDictionary dictionary];
      }
      return _imgCache;
      }

    • (NSOperationQueue *)queue {
      if (!_queue) {
      _queue = [[NSOperationQueue alloc] init];
      // 最大并发数
      _queue.maxConcurrentOperationCount = 3;
      // 对queue的初始化,以及控制子线程最多为3条
      }
      return _queue;

    }```

    这两个方法都是为了初始化刚才的两个属性

    #pragma mark - 数据源方法
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.apps.count;
    }
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        static NSString *ID = @"app";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
        DDZApp *app = self.apps[indexPath.row];
        cell.textLabel.text = app.name;
        cell.detailTextLabel.text = app.download;
        //先从内存中取出图片
        UIImage *image = self.imgCache[app.icon];
        if (image) {
            cell.imageView.image = image;
        }else {
            //内存中没有图片
            //将图片文件数据写入到沙盒中
            NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
            //获得文件名
            NSString *filename = [app.icon lastPathComponent];
            //计算出文件的全路径
            NSString *file = [cachesPath stringByAppendingPathComponent:filename];
            //加载沙盒的文件数据
            NSData *data = [NSData dataWithContentsOfFile:file];
            //判断沙盒中是否有图片
            if (data) {
                //直接加载沙盒中图片
                cell.imageView.image = [UIImage imageWithData:data];
                //存到字典(内存)中
                self.imgCache[app.icon] = cell.imageView.image;
            }else {
    #第一种下载方式
            //下载图片
            data = [NSData dataWithContentsOfURL:[NSURL URLWithString:app.icon]];
            cell.imageView.image = [UIImage imageWithData:data];
            //存到内存中
            self.imgCache[app.icon] = cell.imageView.image;
            //将图片数据写入到沙盒中
            [data writeToFile:file atomically:YES];
    #第二种下载方式
    //下载图片
    //占位图片
    cell.imageView.image = [UIImage imageNamed:@"place.jpg"];
    //先判断是否有下载任务
    //加载失败后可以重复下载
    NSOperation *operation = self.operations[app.icon];
    if (operation == nil) {
    //这张图片没有下载任务
    operation = [NSBlockOperation blockOperationWithBlock:^{
    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:app.icon]];
    //数据加载失败
    if(data == nil) {
    //移除操作
    [self.operations removeObjectForKey:app.icon];
    return ;
    }
    UIImage *image = [UIImage imageWithData:data];
    //存到内存中
    self.imgCache[app.icon] = image;
    //回到主线程显示图片
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
    //会出现重复占位的问题
    //cell.imageView.image = image;
    //只需找到图片所在的行即可
    [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
    }];
    //将图片数据写入到沙盒中
    [data writeToFile:file atomically:YES];
    //移除操作
    [self.operations removeObjectForKey:app.icon];
    }];
    //添加到下载队列
    [self.queue addOperation:operation];
    //添加到字典
    self.operations[app.icon] = operation;
    }
          }
        }
      return cell;
    }```

    相关文章

      网友评论

          本文标题:多线程实现多图片下载

          本文链接:https://www.haomeiwen.com/subject/lgmoettx.html