多线程 NSOperation

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程 NSOperation相关的知识,希望对你有一定的参考价值。

NSOperation是对GCD的分装,OC语言,更简单方便

NSOperation和NSOperationQueue一起使用也能实现多线程编程

基本步骤:

  1. 将操作封装到一个NSOperation对象中
  2. 将NSOperation对象添加到NSOperationQueue队列
  3. 系统会将NSOperationQueue中的NSOperation取出
  4. 将取出的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的主要内容,如果未能解决你的问题,请参考以下文章

iOS开发多线程篇—自定义NSOperation

九使用多线程——NSThread,GCD和NSOperation

iOS开发多线程篇 11 —自定义NSOperation

多线程 NSOperation

多线程-NSOperation

iOS多线程---NSOperation介绍和使用