美文网首页
iOS多线程-NSOperation(转载)

iOS多线程-NSOperation(转载)

作者: 雪影无痕 | 来源:发表于2021-08-24 15:40 被阅读0次

·NSOperation/NSOperationQueue 面向对象的线程技术

·不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上

·NSOperation是面向对象的

iOS中NSOperation详解:https://www.jianshu.com/p/cffd3ace0653

NSOperation是对GCD的objc封装,但是GCD是C语言开发,效率更高,建议如果任务间有依赖关系或者想要监听任务完成状态的情况下使用NSOperation,否则使用GCD。

NSOperation需要配合NSOperationQueue来实现多线程。

NSOperation是一个抽象类,实际使用它的子类,主要有三种方式:

NSInvocationgOperation

NSBlockOperation

自定义继承自NSOperationg的子类,实现内部相应的方法封装任务

相比NSInvocationOperation推荐使用NSBlockOperation,代码更简单,同时由于闭包性使用没有传参问题

1.NSInvocationOperation

单独使用NSInvocationOperation不能开启线程

-(void)viewDidLoad{[superviewDidLoad];NSInvocationOperation*invocationOperatio=[[NSInvocationOperation alloc]initWithTarget:selfselector:@selector(testinvocationOperatio:)object:@{@"type":@"1"}];[invocationOperatio start];}-(void)testinvocationOperatio:(NSDictionary*)dict{NSLog(@"type = %@",dict[@"type"]);}//输出结果2021-05-2714:11:35.785982+0800DJGCDDemo[2347:109547]type=1<NSThread:0x600001410100>{number=1,name=main}

2. NSBlockOperation

使用blockOperationWithBlock不能开启线程

NSBlockOperation*blockOperation=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"block - %@",[NSThread currentThread]);}];[blockOperation start];//输出结果2021-05-2714:15:40.816380+0800DJGCDDemo[2404:113462]block-<NSThread:0x600003094880>{number=1,name=main}

使用addExecutionBlock追加任务是并发执行的,如果这个操作中的任务数量大于1,那么会开启子线程并发执行任务,并且追加的任务不一定就是子线程,也可能是主线程。

NSBlockOperation*blockOperation=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"block - %@",[NSThread currentThread]);}];[blockOperation addExecutionBlock:^{NSLog(@"addBlock - %@",[NSThread currentThread]);}];[blockOperation start];//输出结果2021-05-2714:18:53.825369+0800DJGCDDemo[2439:116303]addBlock-<NSThread:0x6000035641c0>{number=5,name=(null)}2021-05-2714:18:53.825367+0800DJGCDDemo[2439:116227]block-<NSThread:0x600003524640>{number=1,name=main}

3.自定义继承自NSOperation的类

重写main方法

#import"DJOperation.h"@implementationDJOperation-(void)main{NSLog(@"DJOperation = %@",[NSThread currentThread]);}@end

调用时:

DJOperation*dJOperation=[[DJOperationalloc]init];[dJOperation start];//输出结果2021-05-2714:28:17.966533+0800DJGCDDemo[2525:122341]DJOperation=<NSThread:0x600002b94880>{number=1,name=main}

4. NSOperationQueue

NSOperationQueue存放NSOperation的集合类,不能说是队列,不是严格的先进先出,但一般称也为队列。

NSOperationQueue有两种队列:

主队列[NSOperationQueue mainQueue]凡是放到主队列的任务,都在主线程执行。

其他队列[[NSOperationQueue alloc]init]非主队列,通过设置最大并发数maxConcurrentOperationCount来控制任务时并发执行,还是串行执行。

NSInvocationOperation和NSOperationQueue

NSInvocationOperation*invocationOperation=[[NSInvocationOperation alloc]initWithTarget:selfselector:@selector(testinvocationOperatio:)object:@{@"type":@"1"}];NSOperationQueue*queue=[[NSOperationQueue alloc]init];//addOperation方法内部已经调用了[invocationOperatio start],不需要再手动调用[queue addOperation:invocationOperation];//输出结果2021-05-2714:34:52.813297+0800DJGCDDemo[2584:127279]type=1<NSThread:0x6000027f8400>{number=2,name=(null)}

NSBlockOperation和NSOperationQueue

NSBlockOperation*blockOperation=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"block - %@",[NSThread currentThread]);}];[blockOperation addExecutionBlock:^{NSLog(@"addBlock - %@",[NSThread currentThread]);}];NSOperationQueue*queue=[[NSOperationQueue alloc]init];[queue addOperation:blockOperation];//输出结果2021-05-2714:38:47.620228+0800DJGCDDemo[2621:130068]block-<NSThread:0x600002b8b380>{number=8,name=(null)}2021-05-2714:38:47.620267+0800DJGCDDemo[2621:130069]addBlock-<NSThread:0x600002b88740>{number=7,name=(null)}

5.设置最大并发数实现串行

maxConcurrentOperationCount默认为-1,最大值;设置为1时,串行执行;设置为0时,不执行任务。

NSBlockOperation*blockOperation=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"initblock - %@",[NSThread currentThread]);}];[blockOperation addExecutionBlock:^{NSLog(@"addBlock1 - %@",[NSThread currentThread]);}];[blockOperation addExecutionBlock:^{NSLog(@"addBlock2 - %@",[NSThread currentThread]);}];[blockOperation addExecutionBlock:^{NSLog(@"addBlock3 - %@",[NSThread currentThread]);}];NSOperationQueue*queue=[[NSOperationQueue alloc]init];queue.maxConcurrentOperationCount=1;[queue addOperation:blockOperation];//输出结果2021-05-2714:45:44.174409+0800DJGCDDemo[2687:134977]addBlock1-<NSThread:0x6000024d6f80>{number=5,name=(null)}2021-05-2714:45:44.174448+0800DJGCDDemo[2687:134976]initblock-<NSThread:0x600002484100>{number=6,name=(null)}2021-05-2714:45:44.174473+0800DJGCDDemo[2687:134974]addBlock2-<NSThread:0x6000024cd240>{number=4,name=(null)}2021-05-2714:45:44.174501+0800DJGCDDemo[2687:134978]addBlock3-<NSThread:0x60000248fc80>{number=3,name=(null)}

使用addExecutionBlock时,设置最大并发数为1,任务还是并行执行的。

NSBlockOperation*blockOperation1=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"block1 - %@",[NSThread currentThread]);}];NSBlockOperation*blockOperation2=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"block2 - %@",[NSThread currentThread]);}];NSBlockOperation*blockOperation3=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"block3 - %@",[NSThread currentThread]);}];NSBlockOperation*blockOperation4=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"block4 - %@",[NSThread currentThread]);}];NSOperationQueue*queue=[[NSOperationQueue alloc]init];queue.maxConcurrentOperationCount=1;[queue addOperation:blockOperation1];[queue addOperation:blockOperation2];[queue addOperation:blockOperation3];[queue addOperation:blockOperation4];//输出结果2021-05-2714:50:49.288239+0800DJGCDDemo[2744:139236]block1-<NSThread:0x600003639680>{number=5,name=(null)}2021-05-2714:50:49.288396+0800DJGCDDemo[2744:139236]block2-<NSThread:0x600003639680>{number=5,name=(null)}2021-05-2714:50:49.288536+0800DJGCDDemo[2744:139233]block3-<NSThread:0x600003639600>{number=6,name=(null)}2021-05-2714:50:49.288684+0800DJGCDDemo[2744:139236]block4-<NSThread:0x600003639680>{number=5,name=(null)}

队列是按顺序串行执行任务的。串行执行任务不等于只开启一条线程可以开启多条线程,但任务还是串行执行的。

6.暂停、继续和取消

一般存在内容警告时取消队列的操作,或在保证scrollView滚动时流畅,通常在滚动开始时暂停队列中的所有操作,滚动结束后,恢复操作。

(1)NSOperation cancel

NSBlockOperation*blockOperation1=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"block1 - %@",[NSThread currentThread]);}];NSBlockOperation*blockOperation2=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"block2 - %@",[NSThread currentThread]);}];NSBlockOperation*blockOperation3=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"block3 - %@",[NSThread currentThread]);}];NSBlockOperation*blockOperation4=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"block4 - %@",[NSThread currentThread]);}];//取消任务4[blockOperation4 cancel];NSOperationQueue*queue=[[NSOperationQueue alloc]init];queue.maxConcurrentOperationCount=1;[queue addOperation:blockOperation1];[queue addOperation:blockOperation2];[queue addOperation:blockOperation3];[queue addOperation:blockOperation4];//输出结果2021-05-2715:01:59.416162+0800DJGCDDemo[6929:150072]block1-<NSThread:0x600003a96f00>{number=4,name=(null)}2021-05-2715:01:59.416371+0800DJGCDDemo[6929:150074]block2-<NSThread:0x600003ae1ec0>{number=5,name=(null)}2021-05-2715:01:59.416526+0800DJGCDDemo[6929:150074]block3-<NSThread:0x600003ae1ec0>{number=5,name=(null)}

(2)NSOperationQueue取消暂停

//取消所有操作,不可继续执行[queue cancelAllOperations];//暂停队列执行[queue setSuspended:YES];//继续队列执行[queue setSuspended:NO];

暂停操作不能使当前正在执行的任务暂停,而是使后面的任务不会执行,处于排队等待的状态。队列恢复执行后,在继续执行后面的任务。

苹果官方建议,每当执行完一次耗时任务,就查看一下当前队列是否为取消状态,如果是,那么就退出,以此来提高程序的性能。

7.依赖

//任务2依赖于任务4,等待任务执行完成后,在执行任务2// 任务2和任务4可以属于不同队列[blockOperation2 addDependency:blockOperation4];

并且可以在不同的队列中,设置依赖关系,来保证执行顺序。但注意,不可以循环依赖。设置为循环依赖的任务,都不会执行,也不会影响队列的其他任务执行。

8.监听

NSBlockOperation*blockOperation1=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"block1 - %@",[NSThread currentThread]);}];blockOperation1.completionBlock=^{NSLog(@"block1执行完成 %@",[NSThread currentThread]);};NSOperationQueue*queue=[[NSOperationQueue alloc]init];[queue addOperation:blockOperation1];//输出结果2021-05-2715:22:04.073263+0800DJGCDDemo[9079:170313]block1-<NSThread:0x600000738640>{number=6,name=(null)}2021-05-2715:22:04.073441+0800DJGCDDemo[9079:170312]block1执行完成<NSThread:0x60000072e280>{number=4,name=(null)}

监听的任务不一定和被监听的任务在同一线程,都是异步执行的,执行执行完被监听的任务,一定会执行监听任务。

9.addBarrierBlock

类似于dispatch_barrier_async

NSBlockOperation*blockOperation1=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"blockOperation1 = %@",[NSThread currentThread]);}];NSBlockOperation*blockOperation2=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"blockOperation2 = %@",[NSThread currentThread]);}];NSBlockOperation*blockOperation3=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"blockOperation3 = %@",[NSThread currentThread]);}];NSOperationQueue*queue=[[NSOperationQueue alloc]init];[queue addOperation:blockOperation1];[queue addOperation:blockOperation3];//类似于GCD[queue addBarrierBlock:^{NSLog(@"barrierBlock = %@",[NSThread currentThread]);}];[queue addOperation:blockOperation2];//输出结果2021-05-2720:44:54.356190+0800DJGCDDemo[1150:36460]blockOperation3=<NSThread:0x60000266c2c0>{number=3,name=(null)}2021-05-2720:44:54.356194+0800DJGCDDemo[1150:36456]blockOperation1=<NSThread:0x6000026718c0>{number=5,name=(null)}2021-05-2720:44:54.356438+0800DJGCDDemo[1150:36460]barrierBlock=<NSThread:0x60000266c2c0>{number=3,name=(null)}2021-05-2720:44:54.356568+0800DJGCDDemo[1150:36460]blockOperation2=<NSThread:0x60000266c2c0>{number=3,name=(null)}

10.线程间通信

NSBlockOperation*blockOperation1=[NSBlockOperation blockOperationWithBlock:^{NSLog(@"block1 - %@",[NSThread currentThread]);//回到主线程更新UI[[NSOperationQueue mainQueue]addOperationWithBlock:^{NSLog(@"mainQueue = %@",[NSThread currentThread]);}];}];NSOperationQueue*queue=[[NSOperationQueue alloc]init];[queue addOperation:blockOperation1];

11.总结

(1)NSOperation是抽象类,不能直接使用,需要使用其子类。

(2)NSInvocationgOperation和NSBlockOperationg本质没有区别。

(3)NSInvocationgOperation在调用start后,不会开启新的线程,只会在当前线程执行。

(4)NSBlockOperationg在调用start后,如果封装的操作数>1会开启多条线程,=1只会在当前线程执行。

(5)NSOperationQueue创建的操作队列默认为全局队列,队列中的操作执行顺序是无序的,如果需要让它有序,需要添加依赖关系。同时可以设置最大并发数。

12.GCD和NSOperation区别

(1)NSOperation是基于cocoa框架实现的,GCD是基于C语言实现。

(2)NSOperation实现多线程更加面向对象,使用者只需要更多的关注操作本身的处理即可,GCD更加抽象,代码简洁

(3)NSOperation可以通过KVO监控操作进行的状态(准备、执行中、完成、被取消),GCD没有。

(4)NSOperation可以很容易管理各个操作之间的依赖关系,GCD可以通过block嵌套实现,较为复杂

(5)NSOperationQueue可以设置最大并发数,GCD可以通过信号量控制,很麻烦

作者:搬砖的crystal

链接:https://www.jianshu.com/p/f021808dc45b

来源:简书

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

相关文章

网友评论

      本文标题:iOS多线程-NSOperation(转载)

      本文链接:https://www.haomeiwen.com/subject/psmdiltx.html