码迷,mamicode.com
首页 > 其他好文 > 详细

自定义NSOperation

时间:2015-05-13 10:22:54      阅读:207      评论:0      收藏:0      [点我收藏+]

标签:多线程   并行编程   异步   nsoperation   

上一节,我对NSOperation的基本概念及使用进行了介绍,想要了解的,请点击这里。本节中,我介绍自定义NSOperation实现多线程异步下载图片,类似于SDWebImage。

自定义NSOperation的步骤很简单,重写 - (void)main方法,在里面实现想执行的任务。


重写 - (void)main方法注意点:

1.自己创建自动释放池(因为如果是异步操作,无法访问主线程的自动释放池)

2.经常通过 - (BOOL)isCancelled 方法检测操作是否被取消,对取消做出响应。


Demo最终的效果图:

技术分享

上面的图片均是通过NSOperation异步下载的。


下面,我具体介绍代码的实现过程。

1.首先,我准备了数据源(data.plist文件)技术分享


2. 定义了对应的数据模型

@interface DataModel : NSObject

/* 图片名称 */
@property (nonatomic,copy) NSString *name;
/* 图片url地址 */
@property (nonatomic,copy) NSString *url;
/* 下载次数 */
@property (nonatomic,strong) NSNumber *downloadedCount;

// 字典转化为模型
- (instancetype)initWithDict:(NSDictionary *)dict;

@end


@implementation DataModel

- (instancetype)initWithDict:(NSDictionary *)dict {
    if (self = [super init]) {
        // (KVC)字典转模型
        [self setValuesForKeysWithDictionary:dict];
    }
    return  self;
}

@end

3. ViewController中得代码:

#import "ViewController.h"
#import "DataModel.h"
#import "LFDownloadOperation.h"

@interface ViewController ()<LFDownloadOperationDelegate>
/* 数据源 */
@property (nonatomic,strong) NSMutableArray *dataLists;
// Key:url, Value: UIImage (存放图片的缓存字典,有的话,直接取出使用;没有的话,下载)
@property (nonatomic,strong) NSMutableDictionary *images;
// Key:url, Value: LFDownloadOperation
@property (nonatomic,strong) NSMutableDictionary *operations;
// 下载队列,存放LFDownloadOperation
@property (nonatomic,strong) NSOperationQueue *queue;
@end

@implementation ViewController

#pragma mark - Lazy Load
- (NSMutableArray *)dataLists {
    if (!_dataLists) {
        NSString *file = [[NSBundle mainBundle] pathForResource:@"data" ofType:@"plist"];
        NSArray *dataArr = [NSArray arrayWithContentsOfFile:file];
        NSMutableArray *tempLists = [NSMutableArray array];
        for (NSDictionary *dict in dataArr) {
            DataModel *model = [[DataModel alloc] initWithDict:dict];
            [tempLists addObject:model];
        }
        _dataLists = tempLists;
    }
    return _dataLists;
}

- (NSMutableDictionary *)images {
    if (!_images) {
        _images = [NSMutableDictionary dictionary];
    }
    return _images;
}

- (NSMutableDictionary *)operations {
    if( !_operations) {
        _operations = [NSMutableDictionary dictionary];
    }
    return _operations;
}

- (NSOperationQueue *)queue {
    if (!_queue) {
        _queue = [[NSOperationQueue alloc] init];
    }
    return _queue;
}

- (void)viewDidLoad {
    [super viewDidLoad];
}

#pragma mark - UITableView Delegate/DataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return  self.dataLists.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *identifer = @"UITableViewCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifer];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifer];
    }
    
    DataModel *model = self.dataLists[indexPath.row];
    
    cell.textLabel.text = model.name;
    cell.detailTextLabel.text = [model.downloadedCount stringValue];
    
    // 主要实现下载的代码
    UIImage *image = self.images[model.url];
    if (image) { // 图片下载完毕(在字典中)
        cell.imageView.image = image;
    } else {
        // 创建下载Operation并设置默认占位图片
        LFDownloadOperation *operation = self.operations[model.url];
        cell.imageView.image = [UIImage imageNamed:@"placeholder.jpg"];
        
        // 如果operation有值,说明正在下载
        if (!operation) {
            // 还没有下载,立刻创建operation并下载
            operation = [[LFDownloadOperation alloc] init];
            operation.delegate = self;
            operation.url = model.url;
            operation.indexPath = indexPath;
            // 将每张图片的下载地址和每个opearion建立对应关系
            self.operations[model.url] = operation;
            // 不能在这里创建队列,应该只创建一个队列(所以使用懒加载)
            //NSOperationQueue *queue = [[NSOperationQueue alloc] init];
            // 加到队列中并下载
            [self.queue addOperation:operation];
        }
    }
    
    return  cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 130;
}

#pragma mark - LFDownloadOperationDelegate
- (void)downloadOperation:(LFDownloadOperation *)operation didFinishedWithImage:(UIImage *)image {
    NSIndexPath *indexPath = operation.indexPath;
    DataModel *model = self.dataLists[indexPath.row];
    // 当一张图片下载完成了,则应该移除这张图片对应的operation
    [self.operations removeObjectForKey:model.url];
    // 将下载完成的图片保存到images这个字典缓存池中
    self.images[model.url] = image;
    // 每次有图片下载完成,则刷新对应的cell并显示图片
    [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}

@end

4. 自定义的NSOperation

@class LFDownloadOperation;
@protocol LFDownloadOperationDelegate <NSObject>

@optional
/* 代理返回下载完毕的图片 */
- (void)downloadOperation:(LFDownloadOperation *)operation didFinishedWithImage:(UIImage *)image;
@end

@interface LFDownloadOperation : NSOperation

@property (nonatomic,copy) NSString *url;
@property (nonatomic,strong) NSIndexPath *indexPath;
@property (nonatomic,assign) id<LFDownloadOperationDelegate> delegate;

@end

@implementation LFDownloadOperation

// NSOperation中的main就是实现相应的异步操作,所以重写父类方法
- (void)main
{
    // 因为LFDownloadOperation已经不在主线程的自动释放池了,所以要包含在@autoreleasepool中
    @autoreleasepool {
        
        // 取消操作发生在任何时刻都有可能,因此在执行任何操作之前,先检测该操作是否已经被取消
        if (self.isCancelled) {
            return;
        }
        
        NSURL *url = [NSURL URLWithString:self.url];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        
        if (self.isCancelled) {
            return;
        }
        
        if ([self.delegate respondsToSelector:@selector(downloadOperation:didFinishedWithImage:)]){
            dispatch_async(dispatch_get_main_queue(), ^{
                // 最后将异步下载完成的图片返回到主线程(dispatch_get_main_queue)
                [self.delegate downloadOperation:self didFinishedWithImage:image];
            });
        }
    }
}

@end


自定义NSOperation

标签:多线程   并行编程   异步   nsoperation   

原文地址:http://blog.csdn.net/sinat_27706697/article/details/45688573

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!