Operation(Swift)

介绍:

NSOperation须要配合NSOperationQueue来实现多线程。由于默认状况下,NSOperation单独使用时系统同步执行操做,并无开辟新线程的能力,只有配合NSOperationQueue才能实现异步执行。多线程

NSOperation是一个抽象类,并不具有封装操做的能力,必须使用它的子类;并发

由于NSOperation是基于GCD的,那么使用起来也和GCD差很少,其中,NSOperation至关于GCD中的任务,而NSOperationQueue则至关于GCD中的队列。NSOperation实现多线程的使用步骤分为三步:异步

a. 建立任务:先将须要执行的操做封装到一个NSOperation对象中。学习

b. 建立队列:建立NSOperationQueue对象。spa

c. 将任务加入到队列中:而后将NSOperation对象添加到NSOperationQueue中。线程

以后呢,系统就会自动将NSOperationQueue中的NSOperation取出来,在新线程中执行操做。code

 


 

NSOperation是个抽象类,并不能封装任务。咱们只有使用它的子类来封装任务。咱们有三种方式来封装任务。对象

使用子类 NSInvocationOperation
使用子类 NSBlockOperation
定义继承自 NSOperation的子类,经过实现内部相应的方法来封装任务。
在不使用NSOperationQueue,单独使用NSOperation的状况下系统同步执行操做,下面咱们学习如下任务的三种建立方式。

 


 

NSInvocationOperation 

OC版

 1 - (void)testB {
 2 //    建立NSInvocationOperation对象
 3     NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
 4     
 5     // 调用start方法开始执行操做
 6     [op start];
 7 }
 8 
 9 - (void)run
10 {
11     NSLog(@"当前的线程为--%@", [NSThread currentThread]);
12 }

 

结果:blog

2018-01-30 18:46:59.139360+0800 RAC[21774:638747] 当前的线程为--<NSThread: 0x60c000070c00>{number = 1, name = main}

 


 

 

BlockOperation:继承

Swift 版

只要BlockOperation封装的操做数 > 1,就会异步执行操做,可是不会无限制的建立线程

let blockOpe = BlockOperation()
        blockOpe.queuePriority = .veryHigh
        blockOpe.addExecutionBlock {
            print("BlockOperation执行了",Thread.current)
        }
        blockOpe.addExecutionBlock {
            print("BlockOperation2执行了",Thread.current)
        }
        blockOpe.start()  //开始执行
        //blockOpe.cancel() //取消

结果:

 

OC 版

1     NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
2         
3         NSLog(@"-当前的线程为-%@",[NSThread currentThread]);
4     }];
5     
6     [op start];

结果:

在没有使用NSOperationQueue、单独使用NSBlockOperation的状况下,NSBlockOperation也是在主线程执行操做,并无开启新线程。

 

addExecutionBlock

 1 NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
 2         // 在主线程
 3         NSLog(@"线程1------%@", [NSThread currentThread]);
 4     }];
 5     
 6     // 添加额外的任务(在子线程执行)
 7     [op addExecutionBlock:^{
 8         NSLog(@"线程2------%@", [NSThread currentThread]);
 9     }];
10     [op addExecutionBlock:^{
11         NSLog(@"线程3------%@", [NSThread currentThread]);
12     }];
13     [op addExecutionBlock:^{
14         NSLog(@"线程4------%@", [NSThread currentThread]);
15     }];
16     
17     [op start];

结果:

blockOperationWithBlock:方法中的操做是在主线程中执行的,而addExecutionBlock:方法中的操做是在其余线程中执行的

 


 

 

NSOperationQueue

和GCD中的并发队列、串行队列略有不一样的是:NSOperationQueue一共有两种队列:主队列、其余队列。其中其余队列同时包含了串行、并发功能。

建立队列

主队列

获取主队列以及添加操做到队列,主队列是串行队列,不管是否设置最大并行数量都是在当前线程执行,不会建立新的线程

凡是添加到主队列中的任务(NSOperation),都会放到主线程中执行。

1    let queue = OperationQueue.main
2         queue.addOperation {
3             for _ in 0...50000{
4                 print("OperationQueue1执行了",Thread.current)
5             }
6         }

结果:

 

 

其余队列

添加到这种队列中的任务(NSOperation),就会自动放到子线程中执行。同时包含了:串行、并发功能

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

 

a. 

将任务加入到队列中

 

 

同时具有串行和并发的功能,默认状况下是并发的,能够手动设置为串行队列,经过设置最大并发数属性来更改

1 c func racsTest() {
2         let queue = OperationQueue()
3         queue.maxConcurrentOperationCount = 10
4         queue.addOperation {
5             for _ in 0...50000{
6                 print("OperationQueue1执行了",Thread.current)
7             }
8         }
9         //addOperation已经在内部执行了start方法了

结果:


 

最大并发数

a. 取消队列中的全部任务,除了正在执行的任务,一旦被取消,就不能回复以前的操做。

b. 将最大操做数的值设置为1,能够实现任务的串行效果,可是要注意的是,并非只开一条子线程(一般会开两条子线程,循环回收复用)

c. 最大并发数6之内,不要开太多,由于虽然任务是在子线程进行处理的,可是cpu处理这些过多的子线程可能会影响UI,让UI卡顿。

1 queue.maxConcurrentOperationCount=2;

 

队列的取消

当前正在处于执行状态的任务是不可以取消的,只能取消等待的任务

1 queue.cancelAllOperations()

 

队列的挂起和恢复

当前正在处于执行状态的任务是不可以暂停的,只能暂停等待的任务

1 queue.isSuspended = true    //暂停队列
2 queue.isSuspended = false  //恢复队列

 

 

等待Options完成

若是须要在当前线程中处理operation完成后的结果,能够使用NSOperation的waitUntilFinished方法阻塞当前线程,等待operation完成

1 [operation waitUntilFinished];

 

使用NSOperationQueue的waitUntilAllOperationsAreFinished方法

1 // 阻塞当前线程,等待queue的全部操做执行完毕  
2 [queue waitUntilAllOperationsAreFinished];

 


 

 

 

添加NSOperation的依赖对象

当某个NSOperation对象依赖于其它NSOperation对象的完成时,就能够经过 addDependency方法添加一个或者多个依赖的对象,只有全部依赖的对象都已经完成操做,当前NSOperation对象才会开始执行操做。另外,经过 removeDependency方法来删除依赖对象。
 
 1 let queue = OperationQueue()
 2         //设置依赖关系
 3         let blockOpe1 = BlockOperation()
 4         blockOpe1.addExecutionBlock {
 5             print("blockOpe1执行了")
 6         }
 7         let blockOpe2 = BlockOperation()
 8         blockOpe2.addExecutionBlock {
 9             print("blockOpe2执行了")
10         }
11         blockOpe1.addDependency(blockOpe2)
12         queue.addOperation(blockOpe1)
13         queue.addOperation(blockOpe2)
14 //        能够看出,先执行blockOpe2,再执行blockOpe1
15         

结果:

 

 


 

 

 

修改Operations的执行顺序

默认全部operation都拥有“普通”优先级,不过能够经过setQueuePriority:方法来提高或下降operation对象的优先级。

 1         let queue = OperationQueue()
 2         queue.maxConcurrentOperationCount = 3
 3 
 4         let blockOpe = BlockOperation()
 5         blockOpe.addExecutionBlock {
 6             print("blockOpe------------>执行了")
 7         }
 8         blockOpe.queuePriority = .veryHigh
 9         
10         let blockOpe1 = BlockOperation()
11         blockOpe1.addExecutionBlock {
12             print("blockOpe1------------>执行了")
13         }
14         blockOpe1.queuePriority = .low
15         
16         queue.addOperation(blockOpe1)
17         queue.addOperation(blockOpe)

结果:

 

 


 

 

定义NSOperation的子类

 

 1 //    定义一个继承自NSOperation的子类,重写main方法
 2 //    YSCOperation.h
 3 #import <Foundation/Foundation.h>
 4 
 5 @interface YSCOperation : NSOperation
 6 
 7 @end
 8 
 9 
10 //    YSCOperation.m
11 
12 #import "YSCOperation.h"
13 
14 @implementation YSCOperation
15 /**
16  * 须要执行的任务
17  */
18 
19 - (void)main
20 {
21     for (int i = 0; i < 2; ++i) {
22         NSLog(@"--i---%@",[NSThread currentThread]);
23     }    
24 }
25 
26 @end
27 
28 
29 
30 //    导入头文件YSCOperation.h
31 // 建立YSCOperation
32 YSCOperation *op1 = [[YSCOperation alloc] init];
33 
34 [op1 start];

结果:

--0---<NSThread: 0x6080000779c0>{number = 1, name = main}
 --1---<NSThread: 0x6080000779c0>{number = 1, name = main}

在没有使用NSOperationQueue、单独使用自定义子类的状况下,是在主线程执行操做,并无开启新线程。

相关文章
相关标签/搜索
本站公众号
   欢迎关注本站公众号,获取更多信息