ios多線程-NSOperation

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)}
說明任務是都添加隊列後才執行的
發佈了54 篇原創文章 · 獲贊 13 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章