多线程-NSOperationQueue

102 阅读8分钟

ios开发中GCD使用很方便,开发中也应用到,NSOperation是对GCD的封装,主流框架多线程大多是使用NSOperation进行多线程开发

  • NSOperation对比GCD
    • NSOperation基于GCD封装,拥有更多的API
    • 在NSOperationQueue中可以指定NSOperation之间的依赖关系
    • 可以使用KVO监听状态
    • 可定制性,可以继承NSOperation实现可复用的逻辑模块

NSOperation的子类

  • NSInnvocationOperation
  • NSBlockOperation

  1. 使用子类NSInvocationOperation
 NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test) object:nil];
    
    [operation start];
    - (void)test
{
    NSLog(@"%@",[NSThread currentThread]);
}

输出结果

2017-11-02 13:11:27.259 TestApp[7602:842337] <NSThread: 0x600000075b80>{number = 1, name = main}

结果看,单独使用NSInvocationOperation 是在主线程上执行的

2.子类NSBlockOperation

 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        
        NSLog(@"%@",[NSThread currentThread]);
    }];
    
    [operation start];

输出结果

2017-11-02 13:15:31.283 TestApp[7700:865333] <NSThread: 0x608000260380>{number = 1, name = main}

NSBlockOperation 单独一个执行的时候也是在主线程

为NSBlockOperation添加额外的操作 addExecutionBlock

 
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        
        NSLog(@"%@",[NSThread currentThread]);
    }];
   
    
    [operation addExecutionBlock:^{
        NSLog(@"2======%@",[NSThread currentThread]);
    }];
    
    [operation addExecutionBlock:^{
        NSLog(@"3=======%@",[NSThread currentThread]);
    }];
    
     [operation start];
    

输出结果

2017-11-02 13:19:34.229 TestApp[7823:890592] 3=======<NSThread: 0x618000067240>{number = 4, name = (null)}
2017-11-02 13:19:34.228 TestApp[7823:890554] <NSThread: 0x618000065240>{number = 1, name = main}
2017-11-02 13:19:34.229 TestApp[7823:890593] 2======<NSThread: 0x6100000673c0>{number = 3, name = (null)}

可以看到NSBlockOperation在主线程执行,为其添加的操作是在子线程执行的

队列NSOperationQueue

  • 主队列
  • 其他队列 (串行,并发功能)

  • 添加到主队列的任务(nsoperation)都会在主线程执行
    NSOperationQueue *mainqueue = [NSOperationQueue mainQueue];
    
    [mainqueue addOperationWithBlock:^{
        NSLog(@"1=====%@",[NSThread currentThread]);
        
    }];
    
    
    [mainqueue addOperationWithBlock:^{
        NSLog(@"2=======%@",[NSThread currentThread]);
        
    }];
    

输出

2017-11-02 13:27:03.589 TestApp[7979:917764] 1=====<NSThread: 0x6180000755c0>{number = 1, name = main}
2017-11-02 13:27:03.590 TestApp[7979:917764] 2=======<NSThread: 0x6180000755c0>{number = 1, name = main}

验证了,任务添加到主队列添加任务都在主队列

其他队列

    NSOperationQueue *operationQueue = [[NSOperationQueue alloc]init];
    
    NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test) object:nil];
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
       
        for (int i = 0; i < 3; i++) {
            NSLog(@"1====%@",[NSThread currentThread]);
        }
    }];
    
    //添加到队列中
    [operationQueue addOperation:op1];
    [operationQueue addOperation:op2];  
}

- (void)test
{
    for (int i = 0; i < 3; i++) {
        NSLog(@"2====%@",[NSThread currentThread]);
    }
}

输出结果

2017-11-02 13:34:26.810 TestApp[8159:944287] 2====<NSThread: 0x610000071740>{number = 3, name = (null)}
2017-11-02 13:34:26.810 TestApp[8159:944307] 1====<NSThread: 0x618000071b80>{number = 4, name = (null)}
2017-11-02 13:34:26.810 TestApp[8159:944287] 2====<NSThread: 0x610000071740>{number = 3, name = (null)}
2017-11-02 13:34:26.810 TestApp[8159:944307] 1====<NSThread: 0x618000071b80>{number = 4, name = (null)}
2017-11-02 13:34:26.812 TestApp[8159:944307] 1====<NSThread: 0x618000071b80>{number = 4, name = (null)}
2017-11-02 13:34:26.812 TestApp[8159:944287] 2====<NSThread: 0x610000071740>{number = 3, name = (null)}

看到 NSInvocationOperation 与NSBlockOperation 和 NSOperationQueue结合能开辟线程,并发执行任务

3.重点是要说控制部分(串行与并行) NSOperationQueue的串行与并行的控制通过maxConcurrentOperationCount的值大小控制

  • 为-1是默认的值表示不限制为并发执行
  • 为1时为串行执行
  • 大于1时并发执行

NSOperationQueue *queue = [[NSOperationQueue alloc]init]; //设置最大并发操作数 queue.maxConcurrentOperationCount = 1;

//添加操作
[queue addOperationWithBlock:^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"1====%@",[NSThread currentThread]);
        
    }
}];

[queue addOperationWithBlock:^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"2====%@",[NSThread currentThread]);
        
    }
}];


[queue addOperationWithBlock:^{
    for (int i = 0; i < 3; i++) {
        NSLog(@"3====%@",[NSThread currentThread]);
        
    }
}];
为-1时的结果

2017-11-02 14:03:31.215 TestApp[8789:1047083] 2====<NSThread: 0x610000069d00>{number = 4, name = (null)}

2017-11-02 14:03:31.215 TestApp[8789:1047084] 1====<NSThread: 0x608000065f00>{number = 3, name = (null)}

2017-11-02 14:03:31.215 TestApp[8789:1047086] 3====<NSThread: 0x618000067340>{number = 5, name = (null)}

2017-11-02 14:03:31.215 TestApp[8789:1047083] 2====<NSThread: 0x610000069d00>{number = 4, name = (null)}

2017-11-02 14:03:31.215 TestApp[8789:1047084] 1====<NSThread: 0x608000065f00>{number = 3, name = (null)}

2017-11-02 14:03:31.215 TestApp[8789:1047086] 3====<NSThread: 0x618000067340>{number = 5, name = (null)}

2017-11-02 14:03:31.216 TestApp[8789:1047083] 2====<NSThread: 0x610000069d00>{number = 4, name = (null)}

2017-11-02 14:03:31.216 TestApp[8789:1047084] 1====<NSThread: 0x608000065f00>{number = 3, name = (null)}

2017-11-02 14:03:31.216 TestApp[8789:1047086] 3====<NSThread: 0x618000067340>{number = 5, name = (null)}

可以看出线程为并发执行


**为1时的结果**

2017-11-02 14:04:55.051 TestApp[8828:1052683] 1====<NSThread: 0x60000006e040>{number = 3, name = (null)}

2017-11-02 14:04:55.051 TestApp[8828:1052683] 1====<NSThread: 0x60000006e040>{number = 3, name = (null)}

2017-11-02 14:04:55.051 TestApp[8828:1052683] 1====<NSThread: 0x60000006e040>{number = 3, name = (null)}

2017-11-02 14:04:55.051 TestApp[8828:1052683] 2====<NSThread: 0x60000006e040>{number = 3, name = (null)}

2017-11-02 14:04:55.052 TestApp[8828:1052683] 2====<NSThread: 0x60000006e040>{number = 3, name = (null)}

2017-11-02 14:04:55.053 TestApp[8828:1052683] 2====<NSThread: 0x60000006e040>{number = 3, name = (null)}

2017-11-02 14:04:55.053 TestApp[8828:1052680] 3====<NSThread: 0x61000006f400>{number = 4, name = (null)}

2017-11-02 14:04:55.053 TestApp[8828:1052680] 3====<NSThread: 0x61000006f400>{number = 4, name = (null)}

2017-11-02 14:04:55.054 TestApp[8828:1052680] 3====<NSThread: 0x61000006f400>{number = 4, name = (null)}

从结果可以看出线程为串行执行




**大于1时 取值4**

2017-11-02 14:06:49.731 TestApp[8884:1060085] 2====<NSThread: 0x618000065f80>{number = 4, name = (null)}

2017-11-02 14:06:49.731 TestApp[8884:1060115] 1====<NSThread: 0x61000006aa80>{number = 3, name = (null)}

2017-11-02 14:06:49.731 TestApp[8884:1060089] 3====<NSThread: 0x6000000695c0>{number = 5, name = (null)}

2017-11-02 14:06:49.731 TestApp[8884:1060085] 2====<NSThread: 0x618000065f80>{number = 4, name = (null)};

2017-11-02 14:06:49.731 TestApp[8884:1060115] 1====<NSThread: 0x61000006aa80>{number = 3, name = (null)}

2017-11-02 14:06:49.731 TestApp[8884:1060089] 3====<NSThread: 0x6000000695c0>{number = 5, name = (null)}

2017-11-02 14:06:49.732 TestApp[8884:1060085] 2====<NSThread: 0x618000065f80>{number = 4, name = (null)}

2017-11-02 14:06:49.732 TestApp[8884:1060115] 1====<NSThread: 0x61000006aa80>{number = 3, name = (null)}

2017-11-02 14:06:49.732 TestApp[8884:1060089] 3====<NSThread: 0x6000000695c0>{number = 5, name = (null)}

从结果可以看出线程为并行执行


为队列添加依赖(addDependency)

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"1====%@",[NSThread currentThread]);
}];


NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"2====%@",[NSThread currentThread]);
}];

[blockOperation addDependency:op2]; //这里添加依赖,谁在前谁后执行(A依赖B,B先执行 ,B依赖A,A先执行)
[queue addOperation:blockOperation];
[queue addOperation:op2];
输出结果 

2017-11-02 14:13:15.036 TestApp[9035:1091092] 2====<NSThread: 0x600000261ac0>{number = 3, name = (null)}

2017-11-02 14:13:15.037 TestApp[9035:1091120] 1====<NSThread: 0x608000260cc0>{number = 4, name = (null)}

**NSOperationQueue的实例方法**

 cancelAllOperations
 waitUntilAllOperationsAreFinished

首先说(cancelAllOperations)
	 
	

 -(void)cancelAllOperations; NSOperationQueue提供的方法,可以取消队列的所有操作

waitUntilAllOperationsAreFinished

NSLog(@"执行开始");
 NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"1====%@",[NSThread currentThread]);
}];


NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
    for (int i = 0; i < 5; i++) {
    NSLog(@"2====%@",[NSThread currentThread]);
    }
}];

[blockOperation addDependency:op2];
[queue addOperation:blockOperation];
[queue addOperation:op2];
[queue waitUntilAllOperationsAreFinished];

NSLog(@"执行到这了");
执行结果 

2017-11-02 14:23:53.152 TestApp[9349:1143454] 执行开始

2017-11-02 14:23:53.153 TestApp[9349:1143501] 2====<NSThread: 0x608000071f40>{number = 3, name = (null)}

2017-11-02 14:23:53.153 TestApp[9349:1143501] 2====<NSThread: 0x608000071f40>{number = 3, name = (null)}

2017-11-02 14:23:53.153 TestApp[9349:1143501] 2====<NSThread: 0x608000071f40>{number = 3, name = (null)}

2017-11-02 14:23:53.154 TestApp[9349:1143501] 2====<NSThread: 0x608000071f40>{number = 3, name = (null)}

2017-11-02 14:23:53.154 TestApp[9349:1143501] 2====<NSThread: 0x608000071f40>{number = 3, name = (null)}

2017-11-02 14:23:53.154 TestApp[9349:1143514] 1====<NSThread: 0x61800006f740>{number = 4, name = (null)}

2017-11-02 14:23:53.155 TestApp[9349:1143454] 执行到这了

是上面的队列执行完成以后才会执行下面的内容

**再来看一下没有添加    [queue waitUntilAllOperationsAreFinished]; 的执行结果**

2017-11-02 14:31:32.247 TestApp[9512:1179286] 执行开始

2017-11-02 14:31:32.247 TestApp[9512:1179286] 执行到这了

2017-11-02 14:31:32.248 TestApp[9512:1179339] 2====<NSThread: 0x610000074dc0>{number = 3, name = (null)}

2017-11-02 14:31:32.248 TestApp[9512:1179339] 2====<NSThread: 0x610000074dc0>{number = 3, name = (null)}

2017-11-02 14:31:32.248 TestApp[9512:1179339] 2====<NSThread: 0x610000074dc0>{number = 3, name = (null)}

2017-11-02 14:31:32.249 TestApp[9512:1179339] 2====<NSThread: 0x610000074dc0>{number = 3, name = (null)}

2017-11-02 14:31:32.249 TestApp[9512:1179339] 2====<NSThread: 0x610000074dc0>{number = 3, name = (null)}

2017-11-02 14:31:32.250 TestApp[9512:1179356] 1====<NSThread: 0x60000006ee00>{number = 4, name = (null)}

说明任务是都添加队列后才执行的