ios学习笔记——操作队列 NSOperation

NSOperation是一个抽象类,我们不能直接使用。当我们使用NSOperation时有以下三种方式:

1、NSInvocationOperation:NSOperation的子类,可以在使用该类的情况下使用已有方法来执行所需的任务。

2、NSBlockOperation:NSOperation子类,同时执行一个或多个块对象。

3、创建自己的NSOperation子类:

 

所有的NSOperation对象支持以下主要功能:


1、创建对象之间的依赖

2、当operation的主要任务完成后,支持一个可选的block

3、你可以使用KVO通知来监测operation的执行状态的改变

4、设置operation的优先级

5、支持取消,允许在执行时停止操作。

 

使用NSInvocationOperation对象


 1 #import "ViewController.h"
 2 
 3 @interface ViewController ()
 4 
 5 @end
 6 
 7 @implementation ViewController
 8 
 9 - (void)viewDidLoad {
10     [super viewDidLoad];
11     
12     NSString * data = @"shaojiazuo";
13     NSInvocationOperation * operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test:) object:data];
14     
15     //启动opeartion
16     [operation start];
17 }
18 
19 /**
20  *  operation回掉函数
21  *
22  *  @param data opeartaion创建的时候传过来的数据
23  */
24 - (void)test:(NSString *)data
25 {
26     NSLog(@"%@", data);
27 }
28 
29 @end

本例简单使用了NSInvocationOperation对象,调用start方法,可以启动operation,但是不会开启新线程。

输出:

 

使用NSBlockOperation


1 NSBlockOperation * operation = [NSBlockOperation blockOperationWithBlock:^{
2         NSThread * thread = [NSThread currentThread];
3         NSLog(@"%@", thread);
4 }];
5     
6 [operation start];

输出结果:


创建块操作对象后,我们还可以使用addExecutionBlock:方法,添加更多的块。

 1 NSBlockOperation * operation = [NSBlockOperation blockOperationWithBlock:^{
 2         NSThread * thread = [NSThread currentThread];
 3         NSLog(@"1--%@", thread);
 4 }];
 5     
 6 [operation addExecutionBlock:^{
 7         NSThread * thread = [NSThread currentThread];
 8         NSLog(@"2--%@", thread);
 9 }];
10     
11 [operation start];

输出结果:

我们只使用一个block操作的时候,在主线程中执行,不会开始新的线程。一但我们使用了addExecutionBlock:方法,添加了跟多的块的时候,就会自动开启新的线程执行新添加的块代码。

 

自定义Operation对象


 

如果感觉NSInvocationOperation和NSBlockOperation不适用,那么我们可以自定义operation。

实现的工作量取决于你要实现非并发还是并发的NSOpeartion。定义非并发的NSOperation要简单许多,只要重载-(void)main这个方法,在这里面执行主要任务,并正确的响应取消事件。并发NSOperation,必须重写多个基本方法进行实现。

非并发操作

sjzOperation.h

 1 #import <Foundation/Foundation.h>
 2 #import <UIKit/UIKit.h>
 3 
 4 @protocol sjzOperationDeleage <NSObject>
 5 
 6 - (void)downloadFinish:(UIImage *)image;
 7 
 8 @end
 9 
10 @interface sjzOperation : NSOperation
11 
12 @property (nonatomic, strong) NSString * imageUrl;
13 @property (nonatomic, weak) id<sjzOperationDeleage> deleage;
14 
15 - (instancetype)initWithURL:(NSString *)imageUrl;
16 
17 @end

sjzOperation.m

 1 #import "sjzOperation.h"
 2 
 3 @implementation sjzOperation
 4 
 5 - (instancetype)initWithURL:(NSString *)imageUrl
 6 {
 7     self = [super init];
 8     if(self){
 9         self.imageUrl = imageUrl;
10     }
11     
12     return self;
13 }
14 
15 - (void)main
16 {
17     //如果是异步执行操作,那么将无法访问到主线程的自动释放池
18     @autoreleasepool {
19         //线程可能被取消,所以要判断
20         if(self.isCancelled){
21             return;
22         }
23         
24         NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:self.imageUrl]];
25         
26         //在执行比较耗时的操作时,要判断是否取消线程
27         if(self.isCancelled){
28             return;
29         }
30         
31         UIImage * image = [UIImage imageWithData:data];
32         
33         if(self.isCancelled){
34             return;
35         }
36         
37         if([self.deleage respondsToSelector:@selector(downloadFinish:)]){
38             //更改UI要到主线程中
39             [self.deleage performSelector:@selector(downloadFinish:) withObject:image];
40         }
41         
42     }
43 }
44 
45 @end

调用

 1 #import "ViewController.h"
 2 #import "sjzOperation.h"
 3 
 4 @interface ViewController () <sjzOperationDeleage>
 5 
 6 @property (nonatomic, strong) UIImageView * imageView;
 7 
 8 @end
 9 
10 @implementation ViewController
11 
12 - (void)viewDidLoad {
13     [super viewDidLoad];
14     
15     UIImageView * imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
16     self.imageView = imageView;
17     [self.view addSubview:imageView];
18     
19     sjzOperation * operatin = [[sjzOperation alloc] initWithURL:@"http://ww2.sinaimg.cn/crop.0.0.1080.1080.1024/d773ebfajw8eum57eobkwj20u00u075w.jpg"];
20     operatin.deleage = self;
21     [operatin start];
22     
23 }
24 
25 - (void)downloadFinish:(UIImage *)image
26 {
27     self.imageView.image = image;
28 }
29 
30 @end

在mian方法中,添加了好多判断是否取消操作的代码。因为结束操作只有两种可能:1、操作顺利完成,2、取消操作。取消操作可能随时发生,甚至在一个操作开始执行之前,如果一个操作被取消,就不可能回收已经分配的资源。NSOperation对象需要定期地调用isCancelled方法检测操作是否已经被取消,如果返回YES(表示已取消),则立即退出执行。我们可以在下面情况下添加判断是否取消代码:

1、在执行任何实际工作之前

2、如果有循环,在每次循环中都要判断,如果代码比较长,那么判断要更频繁

3、在代码中的任何一个比较容易终止操作的点

 

并发操作

自定义操作,如果想实现并发操作,必须重写以下方法:

1、start方法(必须重写):所有并发操作必须重写此方法,并用自己的自定义实现替换默认行为。要手动执行操作,您调用它的start方法。因此,执行此方法是您的操作的起点,是您在其中设置线程或其他执行环境来执行任务的地方。

2、main方法(选择性重写):此方法通常用于执行与操作对象关联的任务。虽然可以在启动方法中执行任务,但使用该方法执行任务会导致你的设置和任务代码的更清洁分离

3、isExecuting、isFinished(必须重写):并发操作负责建立执行环境,并向外部客户报告该环境情况。因此,一个并发操作必须保持一些状态信息,以知道它合适执行它的任务和它何时完成任务。您的这些方法的实现必须是安全的与其他线程同时调用的时候。你也必须通过这些方法为关键路径创建适当KVO通知。

4、isConcurrent(必须重写):要确定一个操作为并发操作,重写此方法并返回YES。

sjzOperation.h

 1 #import <Foundation/Foundation.h>
 2 #import <UIKit/UIKit.h>
 3 
 4 @protocol sjzOperationDeleage <NSObject>
 5 
 6 - (void)downloadFinish:(UIImage *)image;
 7 
 8 @end
 9 
10 @interface sjzOperation : NSOperation
11 {
12     BOOL executing;
13     BOOL finished;
14 }
15 
16 - (void)completeOperation;
17 
18 @property (nonatomic,  strong) NSString * imageURL;
19 @property (nonatomic, weak) id<sjzOperationDeleage> deleage;
20 
21 - (instancetype)initWithUrl:(NSString *)imageURL;
22 
23 @end

sjzOperation.m

 1 #import "sjzOperation.h"
 2 
 3 @implementation sjzOperation
 4 
 5 - (instancetype)initWithUrl:(NSString *)imageURL
 6 {
 7     self = [super init];
 8     if(self){
 9         self.imageURL = imageURL;
10         executing = NO;
11         finished = NO;
12     }
13     
14     return self;
15 }
16 
17 - (BOOL)isConcurrent
18 {
19     return YES;
20 }
21 
22 //是否开始
23 - (BOOL)isExecuting
24 {
25     return executing;
26 }
27 
28 //是否结束
29 - (BOOL)isFinished
30 {
31     return finished;
32 }
33 
34 - (void)start
35 {
36     //在启动任务前要检查取消
37     if([self isCancelled]){
38         //如果被取消,必须将操作移动到完成状态
39         [self willChangeValueForKey:@"isFinished"];
40         finished = YES;
41         [self didChangeValueForKey:@"isFinished"]; return;
42     }
43     
44     //如果不取消操作,开始执行任务
45     [self willChangeValueForKey:@"isExecuting"];
46     [NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil];
47     executing = YES;
48     [self didChangeValueForKey:@"isExecuting"];
49 }
50 
51 
52 - (void)main
53 {
54     @autoreleasepool {
55         if(self.cancelled){
56             return;
57         }
58         
59         NSThread * thread = [NSThread currentThread];
60         NSLog(@"%@", thread);
61         
62         NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:self.imageURL]];
63         
64         if(self.isCancelled){
65             return;
66         }
67         UIImage * image = [UIImage imageWithData:data];
68         
69         if(self.isCancelled){
70             return;
71         }
72         
73         if([self.deleage respondsToSelector:@selector(downloadFinish:)]){
74             [self.deleage performSelector:@selector(downloadFinish:) withObject:image];
75         }
76         
77         [self completeOperation];
78     }
79 }
80 
81 - (void)completeOperation
82 {
83     [self willChangeValueForKey:@"isFinished"];
84     [self willChangeValueForKey:@"isExecuting"];
85     
86     executing = NO;
87     finished = YES;
88     
89     [self didChangeValueForKey:@"isExecuting"];
90     [self didChangeValueForKey:@"isFinished"];
91 }
92 
93 @end

调用:

 1 #import "ViewController.h"
 2 #import "sjzOperation.h"
 3 
 4 @interface ViewController () <sjzOperationDeleage>
 5 
 6 @property (nonatomic, strong) UIImageView * imageView;
 7 
 8 @end
 9 
10 @implementation ViewController
11 
12 - (void)viewDidLoad {
13     [super viewDidLoad];
14     
15     self.imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
16     [self.view addSubview:self.imageView];
17     
18     sjzOperation * operation = [[sjzOperation alloc] initWithUrl:@"http://ww2.sinaimg.cn/crop.0.0.1080.1080.1024/d773ebfajw8eum57eobkwj20u00u075w.jpg"];
19     operation.deleage = self;
20     [operation start];
21 }
22 
23 - (void)downloadFinish:(UIImage *)image
24 {
25     self.imageView.image = image;
26 }
27 
28 @end

 

posted @ 2016-05-13 17:04  sjzLovecj  阅读(282)  评论(0编辑  收藏  举报