zoukankan      html  css  js  c++  java
  • 自定义NSOperation下载图片

    自定义NSOperation的话,只是需要将要下载图片的操作下载它的main方法里面,考虑到,图片下载完毕,需要回传到控制器里,这里可以采用block,也可以采用代理的方式实现,我采用的是代理的方式实现的。

    重点应该是如何避免同一个url的图片被重复下载?!事实上,可以有这样两个字典,key值是图片的url,value的话,一个字典可以是当前的operation对象,表示,这个url对应的图片正在下载,如果传入图片的url,value不为空的话,说明图片正在下载,那么就不需要再重复下载。另一个字典,可以是存放下载好的图片,也就是常说的缓存,如果一个url取出来的value不为nil,那么这张图片就存在缓存中,不需要再次下载。当然,别忘了设置占位图片~~

    这是model的代码:

    #import <Foundation/Foundation.h>
    
    @interface ZYApp : NSObject
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, copy) NSString *icon;
    @property (nonatomic, copy) NSString *download;
    
    + (id)appWithDict:(NSDictionary *)dict;
    - (id)initWithDict:(NSDictionary *)dict;
    @end
    
    
    #import "ZYApp.h"
    
    @implementation ZYApp
    
    - (id)initWithDict:(NSDictionary *)dict
    {
        if (self = [super init]){
            [self setValuesForKeysWithDictionary:dict];
    //        NSLog(@"%@----%@---%@",self.icon,self.name,self.download);
        }
        return self;
    }
    
    + (id)appWithDict:(NSDictionary *)dict
    {
        return [[self alloc] initWithDict:dict];
    }
    @end
    

     这是自定义的Operation代码:

    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    @class ZYDownLoadImageOperation;
    
    @protocol ZYDownLoadImageOperationDelegate <NSObject>
    @optional
    - (void)DownLoadImageOperation:(ZYDownLoadImageOperation *)operation didFinishDownLoadImage:(UIImage *)image;
    @end
    @interface ZYDownLoadImageOperation : NSOperation
    @property (nonatomic, weak) id<ZYDownLoadImageOperationDelegate> delegate;
    @property (nonatomic, copy) NSString *url;
    @property (nonatomic, strong) NSIndexPath *indexPath;
    @end
    
    #import "ZYDownLoadImageOperation.h"
    
    @implementation ZYDownLoadImageOperation
    - (void)main   //重写main方法即可
    {
        @autoreleasepool {    //在子线程中,并不会自动添加自动释放池,所以,手动添加,免得MARC的情况下,出现内存泄露的问题
            NSURL *DownLoadUrl = [NSURL URLWithString:self.url];
            if (self.isCancelled) return;          //如果下载操作被取消,那么就无需下面操作了
            NSData *data = [NSData dataWithContentsOfURL:DownLoadUrl];
            if (self.isCancelled) return;
            UIImage *image = [UIImage imageWithData:data];
            if (self.isCancelled) return;
            
            if ([self.delegate respondsToSelector:@selector(DownLoadImageOperation:didFinishDownLoadImage:)]) {
                dispatch_async(dispatch_get_main_queue(), ^{   //回到主线程,更新UI
                    [self.delegate DownLoadImageOperation:self didFinishDownLoadImage:image];
                });
            }
        }
    }
    @end
    

     这是控制器代码:

    #import <UIKit/UIKit.h>
    
    @interface ViewController : UIViewController
    
    @end
    
    #import "ViewController.h"
    #import "ZYApp.h"
    #import "ZYDownLoadImageOperation.h"
    
    @interface ViewController () <UITableViewDataSource, UITableViewDelegate, ZYDownLoadImageOperationDelegate, UIScrollViewDelegate>
    @property (weak, nonatomic) IBOutlet UITableView *tableView;
    
    @property (nonatomic, strong) NSArray *apps;
    
    @property (nonatomic, strong) NSOperationQueue *queue;
    
    //  key:图片的url  values: 相对应的operation对象  (判断该operation下载操作是否正在执行,当同一个url地址的图片正在下载,那么不需要再次下载,以免重复下载,当下载操作执行完,需要移除)
    @property (nonatomic, strong) NSMutableDictionary *operations;
    
    //  key:图片的url  values: 相对应的图片        (缓存,当下载操作完成,需要将所下载的图片放到缓存中,以免同一个url地址的图片重复下载)
    @property (nonatomic, strong) NSMutableDictionary *images;
    @end
    
    @implementation ViewController
    
    #define ZYCellIdentifier  @"ZYCellIdentifier"
    - (NSArray *)apps
    {
        if (_apps == nil) {
            NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"apps.plist" ofType:nil]];
            NSMutableArray *tmpArray = [NSMutableArray array];
            for (NSDictionary *dict in dictArray) {
                ZYApp *app = [ZYApp appWithDict:dict];
                [tmpArray addObject:app];
            }
            _apps = tmpArray;
        }
        return _apps;
    }
    
    - (NSOperationQueue *)queue
    {
        if (_queue == nil) {
            _queue = [[NSOperationQueue alloc] init];
            _queue.maxConcurrentOperationCount = 3;
        }
        return _queue;
    }
    
    - (NSMutableDictionary *)operations
    {
        if (_operations == nil) {
            _operations = [NSMutableDictionary dictionary];
        }
        return _operations;
    }
    
    - (NSMutableDictionary *)images
    {
        if (_images == nil) {
            _images = [NSMutableDictionary dictionary];
        }
        return _images;
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        [self setupView];
    }
    
    - (void)setupView
    {
        self.tableView.delegate = self;
        self.tableView.dataSource = self;
    }
    
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return 1;
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return self.apps.count;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ZYCellIdentifier];
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ZYCellIdentifier];
        }
        ZYApp *app = self.apps[indexPath.row];
        cell.textLabel.text = app.name;
        cell.detailTextLabel.text = app.download;
        UIImage *image = self.images[app.icon];
        if (image) {
            cell.imageView.image = image;
        }
        else{
            cell.imageView.image = [UIImage imageNamed:@"TestMam"];
            ZYDownLoadImageOperation *operation = self.operations[app.icon];
            if (operation) {  //正在下载(可以在里面取消下载)
                
            }
            else{ //没有在下载
                operation = [[ZYDownLoadImageOperation alloc] init];
                operation.delegate = self;
                operation.url = app.icon;
                operation.indexPath = indexPath;
                [self.queue addOperation:operation];  //异步下载
                
                self.operations[app.icon] = operation;  //加入字典,表示正在执行此次操作
            }
        }
        return cell;
    }
    
    #pragma mark -- ZYDownLoadImageOperationDelegate
    - (void)DownLoadImageOperation:(ZYDownLoadImageOperation *)operation didFinishDownLoadImage:(UIImage *)image
    {
        [self.operations removeObjectForKey:operation.url];    //下载操作完成,所以把它清掉,表示没有正在下载
        
        if (image){
            self.images[operation.url] = image;    //下载完毕,放入缓存,免得重复下载
            
            [self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationNone];
        }
        
    }
    
    #pragma mark --- UIScrollViewDelegate
    - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
    {
        [self.queue setSuspended:YES];    //在拖拽的时候,停止队列下载
    }
    
    - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
    {
        [self.queue setSuspended:NO];    //在停止拖拽的时候,开始队列下载
    }
    @end
    

     这是此次mode代码github地址:https://github.com/wzpziyi1/CustomOperation

  • 相关阅读:
    jQuery 基本选择器
    JavaScriptif while for switch流程控制 JS函数 内置对象
    JavaScrip基本语法
    数据库 存储引擎 表的操作 数值类型 时间类型 字符串类型 枚举集合 约束
    数据库基础知识 管理员 用户登录授权的操作
    粘包的产生原理 以及如何解决粘包问题
    socket TCP DPT 网络编程
    2018年年终总结
    Android技术分享
    No accelerator found
  • 原文地址:https://www.cnblogs.com/ziyi--caolu/p/4672536.html
Copyright © 2011-2022 走看看