nsoperation封装_NSOperation简单介绍/NSOperation基本操作/自定义NSOperation

NSOperation基本操作

一、并发数

(1)并发数:同时执⾏行的任务数.比如,同时开3个线程执行3个任务,并发数就是3

(2)最大并发数:同一时间最多只能执行的任务的个数。

(3)最⼤大并发数的相关⽅方法

- (NSInteger)maxConcurrentOperationCount;

- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;

说明:如果没有设置最大并发数,那么并发的个数是由系统内存和CPU决定的,可能内存多久开多一点,内存少就开少一点。

注意:num的值并不代表线程的个数,仅仅代表线程的ID。

提示:最大并发数不要乱写(5以内),不要开太多,一般以2~3为宜,因为虽然任务是在子线程进行处理的,但是cpu处理这些过多的子线程可能会影响UI,让UI变卡。

二、队列的取消,暂停和恢复

(1)取消队列的所有操作

- (void)cancelAllOperations;

提⽰:也可以调用NSOperation的- (void)cancel⽅法取消单个操作

(2)暂停和恢复队列

- (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列

- (BOOL)isSuspended; //当前状态

(3)暂停和恢复的适用场合:在tableview界面,开线程下载远程的网络界面,对UI会有影响,使用户体验变差。那么这种情况,就可以设置在用户操作UI(如滚动屏幕)的时候,暂停队列(不是取消队列),停止滚动的时候,恢复队列。

三、操作优先级

(1)设置NSOperation在queue中的优先级,可以改变操作的执⾏优先级

- (NSOperationQueuePriority)queuePriority;

- (void)setQueuePriority:(NSOperationQueuePriority)p;

(2)优先级的取值

NSOperationQueuePriorityVeryLow = -8L,

NSOperationQueuePriorityLow = -4L,

NSOperationQueuePriorityNormal = 0,

NSOperationQueuePriorityHigh = 4,

NSOperationQueuePriorityVeryHigh = 8

说明:优先级高的任务,调用的几率会更大。

四、操作依赖

(1)NSOperation之间可以设置依赖来保证执行顺序,⽐如一定要让操作A执行完后,才能执行操作B,可以像下面这么写

[operationB addDependency:operationA]; // 操作B依赖于操作

(2)可以在不同queue的NSOperation之间创建依赖关系

注意:不能循环依赖(不能A依赖于B,B又依赖于A)。

(3)代码示例

1 #import "YYViewController.h"

2

3 @interface YYViewController ()

4

5 @end

6

7 @implementation YYViewController

8

9 - (void)viewDidLoad

10 {

11 [super viewDidLoad];

12

13 //创建NSInvocationOperation对象,封装操作

14 NSInvocationOperation *operation1=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test1) object:nil];

15 NSInvocationOperation *operation2=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test2) object:nil];

16 //创建对象,封装操作

17 NSBlockOperation *operation3=[NSBlockOperation blockOperationWithBlock:^{

18 for (int i=0; i<5; i++) {

19 NSLog(@"NSBlockOperation3--1----%@",[NSThread currentThread]);

20 }

21 }];

22 [operation3 addExecutionBlock:^{

23 for (int i=0; i<5; i++) {

24 NSLog(@"NSBlockOperation3--2----%@",[NSThread currentThread]);

25 }

26 }];

27

28 //设置操作依赖

29 //先执行operation2,再执行operation1,最后执行operation3

30 [operation3 addDependency:operation1];

31 [operation1 addDependency:operation2];

32

33 //不能是相互依赖

34 // [operation3 addDependency:operation1];

35 // [operation1 addDependency:operation3];

36

37 //创建NSOperationQueue

38 NSOperationQueue * queue=[[NSOperationQueue alloc]init];

39 //把操作添加到队列中

40 [queue addOperation:operation1];

41 [queue addOperation:operation2];

42 [queue addOperation:operation3];

43 }

44

45 -(void)test1

46 {

47 for (int i=0; i<5; i++) {

48 NSLog(@"NSInvocationOperation--test1--%@",[NSThread currentThread]);

49 }

50 }

51

52 -(void)test2

53 {

54 for (int i=0; i<5; i++) {

55 NSLog(@"NSInvocationOperation--test2--%@",[NSThread currentThread]);

56 }

57 }

58

59 @end

打印查看:

A做完再做B,B做完才做C。

注意:一定要在添加之前,进行设置。

提示:任务添加的顺序并不能够决定执行顺序,执行的顺序取决于依赖。使用Operation的目的就是为了让开发人员不再关心线程。

5.操作的监听

可以监听一个操作的执行完毕

- (void (^)(void))completionBlock;

- (void)setCompletionBlock:(void (^)(void))block;

代码示例

第一种方式:可以直接跟在任务后面编写需要完成的操作,如这里在下载图片后,紧跟着下载第二张图片。但是这种写法有的时候把两个不相关的操作写到了一个代码块中,代码的可阅读性不强。

1 #import "YYViewController.h"

2

3 @interface YYViewController ()

4

5 @end

6

7 @implementation YYViewController

8

9 - (void)viewDidLoad

10 {

11 [super viewDidLoad];

12

13 //创建对象,封装操作

14 NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{

15 NSLog(@"-operation-下载图片-%@",[NSThread currentThread]);

16 //.....下载图片后继续进行的操作

17 NSLog(@"--接着下载第二张图片--");

18 }];

19

20 //创建队列

21 NSOperationQueue *queue=[[NSOperationQueue alloc]init];

22 //把任务添加到队列中(自动执行,自动开线程)

23 [queue addOperation:operation];

24 }

25

26 @end

第二种方式:

1 #import "YYViewController.h"

2

3 @interface YYViewController ()

4

5 @end

6

7 @implementation YYViewController

8

9 - (void)viewDidLoad

10 {

11 [super viewDidLoad];

12

13 //创建对象,封装操作

14 NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{

15 for (int i=0; i<10; i++) {

16 NSLog(@"-operation-下载图片-%@",[NSThread currentThread]);

17 }

18 }];

19

20 //监听操作的执行完毕

21 operation.completionBlock=^{

22 //.....下载图片后继续进行的操作

23 NSLog(@"--接着下载第二张图片--");

24 };

25

26 //创建队列

27 NSOperationQueue *queue=[[NSOperationQueue alloc]init];

28 //把任务添加到队列中(自动执行,自动开线程)

29 [queue addOperation:operation];

30 }

31

32 @end

打印查看:

说明:在上一个任务执行完后,会执行operation.completionBlock=^{}代码段,且是在当前线程执行(2)。

自定义NSOperation

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

实现效果展示:

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

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

1 //

2 // YYViewController.h

3 // 01-自定义Operation

4 //

5 // Created by apple on 15-7-29.

6 // Copyright (c) 2015年 itcase. All rights reserved.

7 //

8

9 #import

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-7-29.

6 // Copyright (c) 2015年 itcase. All rights reserved.

7 //

8

9 #import

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 15-7-29.

6 // Copyright (c) 2015年 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-7-29.

6 // Copyright (c) 2015年 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 15-7-29.

6 // Copyright (c) 2015年 itcase. All rights reserved.

7 //

8

9 #import

10

11 #pragma mark-设置代理和代理方法

12 @class YYdownLoadOperation;

13 @protocol YYdownLoadOperationDelegate

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 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 15-7-29.

6 // Copyright (c) 2015年 itcase. All rights reserved.

7 //

8

9 #import "YYViewController.h"

10 #import "YYappModel.h"

11 #import "YYdownLoadOperation.h"

12

13 @interface YYViewController ()

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 15-7-29.

6 // Copyright (c) 2015年 itcase. All rights reserved.

7 //

8

9 #import "YYViewController.h"

10 #import "YYappModel.h"

11 #import "YYdownLoadOperation.h"

12

13 @interface YYViewController ()

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

打印查看:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值