iOS开发多线程篇—自定义NSOperation

一、实现一个简单的tableView显示效果

实现效果展示:

iOS开发多线程篇—自定义NSOperation_自定义


代码示例(使用以前在主控制器中进行业务处理的方式)

1.新建一个项目,让控制器继承自UITableViewController。

iOS开发多线程篇—自定义NSOperation_自定义_02

1 //  2 //  YYViewController.h  3 //  01-自定义Operation  4 //  5 //  Created by apple on 14-6-26.  6 //  Copyright (c) 2014年 itcase. All rights reserved.  7 //  8   9 #import <UIKit/UIKit.h> 10  11 @interface YYViewController : UITableViewController 12  13 @end

iOS开发多线程篇—自定义NSOperation_自定义_02

2.处理storyboard中得界面,如下:

iOS开发多线程篇—自定义NSOperation_ico_04

3.根据plist文件,字典转模型

iOS开发多线程篇—自定义NSOperation_#pragma_05

新建一个类,继承自NSObject,作为数据的模型

YYappModel.h文件

iOS开发多线程篇—自定义NSOperation_自定义_02

1 //  2 //  YYappModel.h  3 //  01-自定义Operation  4 //  5 //  Created by apple on 14-6-26.  6 //  Copyright (c) 2014年 itcase. All rights reserved.  7 //  8   9 #import <Foundation/Foundation.h> 10  11 @interface YYappModel : NSObject 12 /** 13  *应用名称 14  */ 15 @property(nonatomic,copy)NSString *name; 16 /** 17  *  应用图片 18  */ 19 @property(nonatomic,copy)NSString *icon; 20 /** 21  *  应用的下载量 22  */ 23 @property(nonatomic,copy)NSString *download; 24  25 +(instancetype)appModelWithDict:(NSDictionary *)dict; 26 -(instancetype)initWithDict:(NSDictionary *)dict; 27 @end

iOS开发多线程篇—自定义NSOperation_自定义_02

YYappModel.m文件

iOS开发多线程篇—自定义NSOperation_自定义_02

1 //  2 //  YYappModel.m  3 //  01-自定义Operation  4 //  5 //  Created by apple on 14-6-26.  6 //  Copyright (c) 2014年 itcase. All rights reserved.  7 //  8   9 #import "YYappModel.h" 10  11 @implementation YYappModel 12  13 -(instancetype)initWithDict:(NSDictionary *)dict 14 { 15     if (self=[super init]) { 16         [self setValuesForKeysWithDictionary:dict]; 17     } 18     return self; 19 } 20  21 //工厂方法 22 +(instancetype)appModelWithDict:(NSDictionary *)dict 23 { 24     return [[self alloc]initWithDict:dict]; 25 } 26 @end

iOS开发多线程篇—自定义NSOperation_自定义_02

主控制器中得逻辑控制部分,YYViewController.m文件

iOS开发多线程篇—自定义NSOperation_自定义_02

1 //  2 //  YYViewController.m  3 //  01-自定义Operation  4 //  5 //  Created by apple on 14-6-26.  6 //  Copyright (c) 2014年 itcase. All rights reserved.  7 //  8   9 #import "YYViewController.h" 10 #import "YYappModel.h" 11  12 @interface YYViewController () 13 @property(nonatomic,strong)NSArray *apps; 14  15 @end 16  17 @implementation YYViewController 18 #pragma mark- 懒加载 19 -(NSArray *)apps 20 { 21     if (_apps==nil) { 22         NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil]; 23         NSArray *tempArray=[NSArray arrayWithContentsOfFile:path]; 24          25         //字典转模型 26         NSMutableArray *array=[NSMutableArray array]; 27         for (NSDictionary *dict in tempArray) { 28             YYappModel *app=[YYappModel appModelWithDict:dict]; 29             [array addObject:app]; 30         } 31         _apps=array; 32     } 33     return _apps; 34 } 35  36 #pragma mark-数据源方法 37 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 38 { 39     return self.apps.count; 40 } 41  42 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 43 { 44     static NSString *ID=@"ID"; 45     UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID]; 46     if (cell==nil) { 47         cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID]; 48     } 49     YYappModel *app=self.apps[indexPath.row]; 50     cell.textLabel.text=app.name; 51     cell.detailTextLabel.text=app.download; 52      53     //下载图片数据 54     NSLog(@"加载图片数据---%@", [NSThread currentThread]); 55     NSURL *url=[NSURL URLWithString:app.icon]; 56     NSData *data=[NSData dataWithContentsOfURL:url]; 57     UIImage *imgae=[UIImage imageWithData:data]; 58     cell.imageView.image=imgae; 59     NSLog(@"完成显示"); 60     return cell; 61 } 62  63 @end

iOS开发多线程篇—自定义NSOperation_自定义_02

打印查看:

iOS开发多线程篇—自定义NSOperation_自定义_12

二、自定义NSOperation

说明:上面的下载图片数据部分是一个非常耗时的操作,这个操作任务在主线程完成,会严重的影响到用户体验,造成UI卡的现象。下面通过自定义NSOperation,新开线程,让加载图片的任务异步执行。

1.通过代理

在上面的基础上,新建一个类,让其继承自NSOperation。

YYdownLoadOperation.h文件

iOS开发多线程篇—自定义NSOperation_自定义_02

1 //  2 //  YYdownLoadOperation.h  3 //  01-自定义Operation  4 //  5 //  Created by apple on 14-6-26.  6 //  Copyright (c) 2014年 itcase. All rights reserved.  7 //  8   9 #import <Foundation/Foundation.h> 10  11 #pragma mark-设置代理和代理方法 12 @class YYdownLoadOperation; 13 @protocol YYdownLoadOperationDelegate <NSObject> 14 -(void)downLoadOperation:(YYdownLoadOperation*)operation didFishedDownLoad:(UIImage *)image; 15 @end 16  17 @interface YYdownLoadOperation : NSOperation 18 @property(nonatomic,copy)NSString *url; 19 @property(nonatomic,strong)NSIndexPath *indexPath; 20 @property(nonatomic,strong)id <YYdownLoadOperationDelegate> delegate; 21 @end

iOS开发多线程篇—自定义NSOperation_自定义_02

YYdownLoadOperation.m文件

iOS开发多线程篇—自定义NSOperation_自定义_02

1 //  2 //  YYdownLoadOperation.m  3 //  01-自定义Operation  4 //  5 //  Created by apple on 14-6-26.  6 //  Copyright (c) 2014年 itcase. All rights reserved.  7 //  8   9 #import "YYdownLoadOperation.h" 10  11 @implementation YYdownLoadOperation 12 -(void)main 13 { 14     NSURL *url=[NSURL URLWithString:self.url]; 15     NSData *data=[NSData dataWithContentsOfURL:url]; 16     UIImage *imgae=[UIImage imageWithData:data]; 17      18     NSLog(@"--%@--",[NSThread currentThread]); 19     //图片下载完毕后,通知代理 20     if ([self.delegate respondsToSelector:@selector(downLoadOperation:didFishedDownLoad:)]) { 21         dispatch_async(dispatch_get_main_queue(), ^{//回到主线程,传递数据给代理对象 22              [self.delegate downLoadOperation:self didFishedDownLoad:imgae]; 23         }); 24     } 25 } 26 @end

iOS开发多线程篇—自定义NSOperation_自定义_02

主控制器中的业务逻辑:

iOS开发多线程篇—自定义NSOperation_自定义_02

1 //  2 //  YYViewController.m  3 //  01-自定义Operation  4 //  5 //  Created by apple on 14-6-26.  6 //  Copyright (c) 2014年 itcase. All rights reserved.  7 //  8   9 #import "YYViewController.h" 10 #import "YYappModel.h" 11 #import "YYdownLoadOperation.h" 12  13 @interface YYViewController ()<YYdownLoadOperationDelegate> 14 @property(nonatomic,strong)NSArray *apps; 15 @property(nonatomic,strong)NSOperationQueue *queue; 16  17 @end 18  19 @implementation YYViewController 20 #pragma mark- 懒加载apps 21 -(NSArray *)apps 22 { 23     if (_apps==nil) { 24         NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil]; 25         NSArray *tempArray=[NSArray arrayWithContentsOfFile:path]; 26          27         //字典转模型 28         NSMutableArray *array=[NSMutableArray array]; 29         for (NSDictionary *dict in tempArray) { 30             YYappModel *app=[YYappModel appModelWithDict:dict]; 31             [array addObject:app]; 32         } 33         _apps=array; 34     } 35     return _apps; 36 } 37  38 #pragma mark-懒加载queue 39 -(NSOperationQueue *)queue 40 { 41     if (_queue==Nil) { 42         _queue=[[NSOperationQueue alloc]init]; 43         //设置最大并发数为3 44         _queue.maxConcurrentOperationCount=3; 45     } 46     return _queue; 47 } 48  49 #pragma mark-数据源方法 50 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 51 { 52     return self.apps.count; 53 } 54 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 55 { 56     static NSString *ID=@"ID"; 57     UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID]; 58     if (cell==nil) { 59         cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID]; 60     } 61     YYappModel *app=self.apps[indexPath.row]; 62     cell.textLabel.text=app.name; 63     cell.detailTextLabel.text=app.download; 64      65     //下载图片数据 66 //    NSLog(@"加载图片数据---%@", [NSThread currentThread]); 67 //    NSURL *url=[NSURL URLWithString:app.icon]; 68 //    NSData *data=[NSData dataWithContentsOfURL:url]; 69 //    UIImage *imgae=[UIImage imageWithData:data]; 70 //    cell.imageView.image=imgae; 71      72     //创建一个OPeration对象 73     YYdownLoadOperation *operation=[[YYdownLoadOperation alloc]init]; 74     operation.url=app.icon; 75     operation.indexPath=indexPath; 76     operation.delegate=self; 77      78     //把操作对象添加到队列中在去 79     [self.queue addOperation:operation]; 80  81 //    NSLog(@"完成显示"); 82     return cell; 83 } 84 -(void)downLoadOperation:(YYdownLoadOperation *)operation didFishedDownLoad:(UIImage *)image 85 { 86     //返回图片数据给每行对应的cell的imageview.image 87     //取出tableview中indexPath这一行对应的cell 88     UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:operation.indexPath]; 89     //显示图片 90     cell.imageView.image=image; 91 //    NSLog(@"cell--index--%@---%@",operation.indexPath,[NSThread currentThread]); 92     //一定要刷新表格 93     [self.tableView reloadData]; 94     NSLog(@"--%@--",[NSThread currentThread]); 95  96 } 97 @end

iOS开发多线程篇—自定义NSOperation_自定义_02

说明:通过打印可以发现上面的代码存在很大的问题。

问题1:需要保证一个url对应一个operation对象。

问题2:下载完需要移除。移除执行完毕的操作。

问题3:保证一个url对应一个image。 下面对主控制器中得代码进行改进: iOS开发多线程篇—自定义NSOperation_自定义_02

1 //   2 //  YYViewController.m   3 //  01-自定义Operation   4 //   5 //  Created by apple on 14-6-26.   6 //  Copyright (c) 2014年 itcase. All rights reserved.   7 //   8    9 #import "YYViewController.h"  10 #import "YYappModel.h"  11 #import "YYdownLoadOperation.h"  12   13 @interface YYViewController ()<YYdownLoadOperationDelegate>  14 @property(nonatomic,strong)NSArray *apps;  15 @property(nonatomic,strong)NSOperationQueue *queue;  16 @property(nonatomic,strong)NSMutableDictionary *operations;  17 @property(nonatomic,strong)NSMutableDictionary *images;  18   19 @end  20   21 @implementation YYViewController  22 #pragma mark- 懒加载apps  23 -(NSArray *)apps  24 {  25     if (_apps==nil) {  26         NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil];  27         NSArray *tempArray=[NSArray arrayWithContentsOfFile:path];  28           29         //字典转模型  30         NSMutableArray *array=[NSMutableArray array];  31         for (NSDictionary *dict in tempArray) {  32             YYappModel *app=[YYappModel appModelWithDict:dict];  33             [array addObject:app];  34         }  35         _apps=array;  36     }  37     return _apps;  38 }  39   40 #pragma mark-懒加载queue  41 -(NSOperationQueue *)queue  42 {  43     if (_queue==Nil) {  44         _queue=[[NSOperationQueue alloc]init];  45         //设置最大并发数为3  46         _queue.maxConcurrentOperationCount=3;  47     }  48     return _queue;  49 }  50   51 #pragma mark-懒加载operations  52 -(NSMutableDictionary *)operations  53 {  54     if (_operations==Nil) {  55         _operations=[NSMutableDictionary dictionary];  56     }  57     return _operations;  58 }  59   60 #pragma mark-懒加载images  61 -(NSMutableDictionary *)images  62 {  63     if (_images==Nil) {  64         _images=[NSMutableDictionary dictionary];  65     }  66     return _images;  67 }  68   69 #pragma mark-数据源方法  70 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section  71 {  72     return self.apps.count;  73 }  74 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath  75 {  76     static NSString *ID=@"ID";  77     UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID];  78     if (cell==nil) {  79         cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];  80     }  81     YYappModel *app=self.apps[indexPath.row];  82     cell.textLabel.text=app.name;  83     cell.detailTextLabel.text=app.download;  84       85     //保证一个url对应一个image对象  86     UIImage *image=self.images[app.icon];  87     if (image) {//缓存中有图片  88         cell.imageView.image=image;  89     }else       //  缓存中没有图片,得下载  90     {  91         //先设置一张占位图片  92         cell.imageView.image=[UIImage imageNamed:@"57437179_42489b0"];  93         YYdownLoadOperation *operation=self.operations[app.icon];  94         if (operation) {//正在下载  95             //什么都不做  96         }else  //当前没有下载,那就创建操作  97         {  98             operation=[[YYdownLoadOperation alloc]init];  99             operation.url=app.icon; 100             operation.indexPath=indexPath; 101             operation.delegate=self; 102             [self.queue addOperation:operation];//异步下载 103             self.operations[app.icon]=operation; 104         } 105     } 106      107  108     return cell; 109 } 110 -(void)downLoadOperation:(YYdownLoadOperation *)operation didFishedDownLoad:(UIImage *)image 111 { 112     //1.移除执行完毕的操作 113     [self.operations removeObjectForKey:operation.url]; 114      115     //2.将图片放到缓存中 116     self.images[operation.url]=image; 117  118     //3.刷新表格(只刷新下载的那一行) 119      120     [self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 121     NSLog(@"--%d--%@--",operation.indexPath.row,[NSThread currentThread]); 122  123 } 124 @end

iOS开发多线程篇—自定义NSOperation_自定义_02

打印查看:

iOS开发多线程篇—自定义NSOperation_#pragma_21