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

    上一篇文章的下载图片操作都放在了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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值