iOS开发实践之cell下载图片(自定义NSOperation)

来源:互联网 发布:数据库isnull 编辑:程序博客网 时间:2024/05/14 03:30

    上一篇文章的下载图片操作都放在了block中,当遇到复杂的操作,一堆的代码放在block中 ,很明显这不是明智的选择,代码显得很臃肿。 因此,把线程操作放到自定义NSOperation中。


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

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

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

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


案例代码:

  1、新建DownloadOperation继承NSOperation,下载操作放到main方法中。 至于下载后回到主线程要做点什么,它自己本身不知道(不是它的工作范畴)。只负责下载完成后通知其它人,因此委托代理,委托别人去做事。

DownloadOperation.h

#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>@class DownloadOperation;//协议@protocol DownloadOperationDelegate <NSObject>@optional- (void)downloadOperation:(DownloadOperation *)operation didFinishDownload:(UIImage *)image;@end@interface DownloadOperation : NSOperation//下载图片地址@property(nonatomic,copy) NSString *imageUrl;//表格cell位置@property(nonatomic,strong) NSIndexPath *indexPath;//代理@property(nonatomic,weak) id<DownloadOperationDelegate> delegate;@end


DownloadOperation.m      

注意:@autoreleasepool 自动释放池 、isCancelled方法检测操作是否被取消,对取消做出响应。

#import "DownloadOperation.h"#import <UIKit/UIKit.h>@implementation DownloadOperation-(void)main{    @autoreleasepool {//管理内存        if (self.isCancelled)  return;  //暂停为执行的操作                NSURL *url = [NSURL URLWithString:self.imageUrl];        NSData *data = [NSData dataWithContentsOfURL:url]; // 下载        UIImage *image = [UIImage imageWithData:data]; // NSData -> UIImage                if(self.isCancelled) return;//暂停正在执行的操作                // 回到主线程        [[NSOperationQueue mainQueue] addOperationWithBlock:^{            if ([self.delegate respondsToSelector:@selector(downloadOperation:didFinishDownload:)]) {                [self.delegate downloadOperation:self didFinishDownload:image];            }        }];    }}@end


2、AppsTableViewController.m

////  AppsTableViewController.m//  cell图片下载(自定义operation)#import "AppsTableViewController.h"#import "App.h"#import "DownloadOperation.h"@interface AppsTableViewController ()<DownloadOperationDelegate>//应用信息集合@property(nonatomic,strong) NSMutableArray *apps;//存放所有下载图片的队列@property(nonatomic,strong) NSOperationQueue *queue;//存放所有的下载操作(url是key,operation对象是value)@property(nonatomic,strong) NSMutableDictionary *operations;//存放所有下载完的图片@property(nonatomic,strong) NSMutableDictionary *images;@end@implementation AppsTableViewController- (void)viewDidLoad {    [super viewDidLoad];       }- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}/** * 懒加载 **/-(NSMutableArray *)apps{    if (!_apps) {        NSMutableArray *appArr = [NSMutableArray array];        NSString *file =[[NSBundle mainBundle] pathForResource:@"apps" ofType:@"plist"];        NSArray *dictArr = [NSArray arrayWithContentsOfFile:file];        for (NSDictionary *dict in dictArr) {            App *app = [App appWithDict:dict];            [appArr addObject:app];        }        _apps = appArr;    }    return _apps;}-(NSOperationQueue *)queue{    if (!_queue) {        _queue = [[NSOperationQueue alloc]init];    }    return _queue;}-(NSMutableDictionary *)operations{    if (!_operations) {        _operations = [[NSMutableDictionary alloc]init];    }    return _operations;}-(NSMutableDictionary *)images{    if (!_images) {        _images = [[NSMutableDictionary alloc]init];    }    return _images;}#pragma mark - Table view data source- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {    return 1;}- (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];    if (!cell) {        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];    }        App *app = self.apps[indexPath.row];    cell.textLabel.text = app.name;    cell.detailTextLabel.text = app.download;        // 先从images缓存中取出图片url对应的UIImage    UIImage *image = self.images[app.icon];    if (image) {// 说明图片已经下载成功过(成功缓存)        cell.imageView.image = image;    }else{        // 获得caches的路径, 拼接文件路径        NSString *file = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[app.icon lastPathComponent]];                // 先从沙盒中取出图片        NSData *data = [NSData dataWithContentsOfFile:file];        if (data) {//沙盒中存在图片            cell.imageView.image = [UIImage imageWithData:data];        }else{//沙盒不存,进行下载操作            //显示占位图片            cell.imageView.image = [UIImage imageNamed:@"placeholder"];                        // 下载图片            [self download:app.icon indexPath:indexPath];        }            }    return cell;}-(void)download:(NSString *)imageUrl indexPath:(NSIndexPath *)indexPath{    //取出当前图片url对应下的下载操作(operations对象)    DownloadOperation *operation = self.operations[imageUrl];    if (operation)  return; //如果存在操作就不往下执行(因为可能该图片下载操作正在进行)        //创建操作,下载图片    operation = [[DownloadOperation alloc]init];    operation.imageUrl = imageUrl;    operation.indexPath = indexPath;        //设置代理    operation.delegate = self;        // 添加操作到队列中    [self.queue addOperation:operation];         // 添加到字典中 (这句代码为了解决重复下载)    self.operations[imageUrl] = operation;        }/** *  当用户开始拖拽表格时调用 */-(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{  //暂停下载    [self.queue setSuspended:YES];}/** *  当用户停止拖拽表格时调用 */-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{    //开始下载    [self.queue setSuspended:NO];}#pragma mark - 下载操作的代理方法-(void)downloadOperation:(DownloadOperation *)operation didFinishDownload:(UIImage *)image{    // 存放图片到字典中    if (image) {        //存放所有的下载操作        self.operations[operation.imageUrl] = image;                //将图片存入沙盒中        NSData *data = UIImagePNGRepresentation(image);        NSString *file = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)lastObject]stringByAppendingPathComponent:[operation.imageUrl lastPathComponent]];        [data writeToFile:file atomically:YES];    }        // 从字典中移除下载操作 (防止operations越来越大,保证下载失败后,能重新下载)    [self.operations removeObjectForKey:operation.imageUrl];        // 刷新表格    [self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationNone];}@end



  


0 0
原创粉丝点击