博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Operation(Swift)
阅读量:4343 次
发布时间:2019-06-07

本文共 5966 字,大约阅读时间需要 19 分钟。

介绍:

NSOperation需要配合NSOperationQueue来实现多线程。因为默认情况下,NSOperation单独使用时系统同步执行操作,并没有开辟新线程的能力,只有配合NSOperationQueue才能实现异步执行。

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

因为NSOperation是基于GCD的,那么使用起来也和GCD差不多,其中,NSOperation相当于GCD中的任务,而NSOperationQueue则相当于GCD中的队列。NSOperation实现多线程的使用步骤分为三步:

a. 创建任务:先将需要执行的操作封装到一个NSOperation对象中。

b. 创建队列:创建NSOperationQueue对象。

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

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

 


 

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)run10 {11     NSLog(@"当前的线程为--%@", [NSThread currentThread]);12 }

 

结果:

2018-01-30 18:46:59.139360+0800 RAC[21774:638747] 当前的线程为--
{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.main2         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 = 104         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,再执行blockOpe115

结果:

 

 


 

 

 

修改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 = .low15         16         queue.addOperation(blockOpe1)17         queue.addOperation(blockOpe)

结果:

 

 


 

 

定义NSOperation的子类

 

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

结果:

--0---
{number = 1, name = main} --1---
{number = 1, name = main}

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

 

转载于:https://www.cnblogs.com/EchoHG/p/8378843.html

你可能感兴趣的文章
三极管动画
查看>>
手把手玩转win8开发系列课程(11)
查看>>
Linux Namespace : User
查看>>
交换两个整形变量的数值
查看>>
Linux----常用操作
查看>>
sequence
查看>>
Delphi错误:Stack overflow的解决方法
查看>>
一篇很全面的freemarker教程
查看>>
取消chrome(谷歌浏览器)浏览器下最小字体限制
查看>>
模板方法模式
查看>>
什么是ECC内存?
查看>>
使用Visual Studio 2013进行UI自动化测试
查看>>
13-集体照
查看>>
读了曾国藩家书,,心态逐渐平和起来。搞技术的如果缺乏信念的指引,生活会很乏味无聊!...
查看>>
前端javascript 错误 Uncaught SyntaxError: Unexpected token ILLEGAL
查看>>
Selenium WebDriver问题--无法打开Chrome浏览器
查看>>
2017.4.18 Java的Integer与int互转
查看>>
小程序接受返回数组的坑
查看>>
Arduino---HC-05 蓝牙模块
查看>>
构建之法读书笔记02——个人技术和流程
查看>>