IOS多线程之NSOperation(自定义)

转载自: http://www.cnblogs.com/wendingding/p/3811121.html ;
一、实现一个简单的tableView显示效果

实现效果展示:


 

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

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


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

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


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


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

YYappModel.h文件


 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

YYappModel.m文件


 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

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


 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

打印查看:


二、自定义NSOperation

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

1.通过代理

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

YYdownLoadOperation.h文件


 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

YYdownLoadOperation.m文件


 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

主控制器中的业务逻辑:


 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

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

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

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

问题3:保证一个url对应一个image。
下面对主控制器中得代码进行改进:

 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

打印查看:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值