自定义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

原文地址:https://www.cnblogs.com/ziyi--caolu/p/4672536.html