ios開發中GCD使用很方便,開發中也應用到,NSOperation是對GCD的封裝,主流框架多線程大多是使用NSOperation進行多線程開發
- NSOperation對比GCD
- NSOperation基於GCD封裝,擁有更多的API
- 在NSOperationQueue中可以指定NSOperation之間的依賴關係
- 可以使用KVO監聽狀態
- 可定製性,可以繼承NSOperation實現可複用的邏輯模塊
NSOperation的子類
- NSInnvocationOperation
- NSBlockOperation
- 使用子類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)}
說明任務是都添加隊列後才執行的