多线程 NSOperation
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程 NSOperation相关的知识,希望对你有一定的参考价值。
NSOperation是对GCD的分装,OC语言,更简单方便
NSOperation和NSOperationQueue一起使用也能实现多线程编程
基本步骤:
- 将操作封装到一个NSOperation对象中
- 将NSOperation对象添加到NSOperationQueue队列
- 系统会将NSOperationQueue中的NSOperation取出
- 将取出的NSOperation封装的操作放到一条新线程中执行
NSOperation是一个抽象类,不具备操作能力,必须使用它的子类:
- NSInvocationOperation
- NSBlockOperation(使用的最多)
- 自定义子类继承于NSOperation,实现相应的方法(使用较少)
1.NSInvocationOperation:
- (void)InvocationOperation { //创建队列,通过alloc init方式创建的队列是并发队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init];
for(int i = 0; i < 5; i++) { //创建操作 NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test) object:nil]; //把操作放到队列中 [queue addOperation:op]; } } - (void)test { NSLog(@"当前线程 = %@",[NSThread currentThread]); }
打印可以验证queue是一个并发队列
2.NSBlockOperation
- (void)BlockOperation { //创建队列,通过alloc init方式创建的队列是并发队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; for(int i = 0; i < 5; i++) { //创建操作 NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"当前线程 = %@",[NSThread currentThread]); }]; //把操作放到队列中 [queue addOperation:op]; } }
也可以这样使用(更简单)
- (void)BlockOperationEasy { //创建队列,通过alloc init方式创建的队列是并发队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperationWithBlock:^{ NSLog(@"当前线程 = %@",[NSThread currentThread]); }]; }
添加一个额外的操作
- (void)BlockOperation { //创建队列,通过alloc init方式创建的队列是并发队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //创建操作 NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"当前线程 = %@",[NSThread currentThread]); }]; //再添加一个操作 [op addExecutionBlock:^{ NSLog(@"这是一个额外的操作,线程 = %@",[NSThread currentThread]); }]; //把操作放到队列中 [queue addOperation:op]; }
NSOperationQueue:
NSOperationQueue没有串行队列,但是它可以获取主队列,通过下面代码获取到主队列,添加到主队列中的任务都会在主线程中执行
[NSOperationQueue mainQueue]
线程间通讯 :
- (void)refreshUI { NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperationWithBlock:^{ NSLog(@"多线程中执行的操作%@",[NSThread currentThread]); [[NSOperationQueue mainQueue] addOperationWithBlock:^{ NSLog(@"回到主线程更新UI%@",[NSThread currentThread]); }]; }]; }
最大并发数:
- 并发数是指同时执行任务的数量
- 比如同时开启3个线程执行3个任务,并发数就是3
- NSOperation可以通过最大并发数控制同一时间执行操作数量
- (void)max { NSOperationQueue *queue = [[NSOperationQueue alloc] init]; queue.maxConcurrentOperationCount = 2; for (int i = 0; i< 10; i++) { [queue addOperationWithBlock:^{ NSLog(@"i = %d, thread = %@",i,[NSThread currentThread]); }]; } }
结果出现了2,3,4,5四个线程,这是因为最大并发决定的是同一时间执行操作数量,而不是线程的数量;
挂起队列:
- 挂机队列是把任务保存在当前状态,之后可以继续
- 挂起操作不会影响已经在执行的任务
- (void)suspended { NSOperationQueue *queue = [[NSOperationQueue alloc] init]; for (int i = 0; i< 10; i++) { if (i == 5) { //挂起队列 queue.suspended = YES; //延迟2s [NSThread sleepForTimeInterval:2]; //继续 queue.suspended = NO; } [queue addOperationWithBlock:^{ NSLog(@"i = %d, thread = %@",i,[NSThread currentThread]); }]; } }
取消操作
- 取消操作并不会影响队列的挂起状态
- (如果队列是挂起状态)一般取消操作后会把队列置于不挂起状态,便于后续操作
- 挂起队列,队列中的任务还存在,可以继续;取消操作,队列中的任务就没有了,只能重新添加任务
- (void)cancel { NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //设置最大并发数为1 queue.maxConcurrentOperationCount = 1; for (int i = 0; i< 10; i++) { [queue addOperationWithBlock:^{ [NSThread sleepForTimeInterval:1]; NSLog(@"i = %d, thread = %@",i,[NSThread currentThread]); }]; } //3S后取消队列里的所有操作 [NSThread sleepForTimeInterval:3]; [queue cancelAllOperations]; }
打印结果可以看出后面的操作都已经被取消了
依赖关系 :
- 依赖关系可以跨队列
- 注意不要循环依赖
- (void)dependecy { NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSBlockOperation *one = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"下载音乐"); }]; NSBlockOperation *two = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"打开音乐"); }]; NSBlockOperation *three = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"播放音乐"); }]; //添加任务依赖关系 [two addDependency:one]; [three addDependency:two]; //等待任务完成继续下一个任务,类似于GCD里的调度组 [queue addOperations:@[one,two,three] waitUntilFinished:YES]; NSLog(@"听完音乐放松一下"); }
以上是关于多线程 NSOperation的主要内容,如果未能解决你的问题,请参考以下文章