iOS - NSOperation與NSOperationQueue

b10l07發表於2015-09-02
作者:Mitchell 

一、NSOperation簡介

  • NSOperation 的作用
    配合使用 NSOperation 和 NSOperationQueue 也能實現多執行緒程式設計
  • NSOperation 和 NSOperationQueue 實現多執行緒的具體步驟
  • 先將需要執行的操作封裝到一個 NSOperation 物件中
  • 然後將 NSOperation 物件新增到 NSOperationQueue 中
  • 系統會自動將 NSOperationQueue 中的 NSOperation 取出來
  • 將取出來的 NSOperation 封裝的操作放到一條新執行緒中執行
  • 簡單建立:
    • 建立佇列
      • 自己建立:alloc/init --> 預設是併發 -->也可以序列
      • 主對列:mainQueue
      • 因為NSOperation 沒有新增方法不能封裝操作所以不能直接使用,兩種任務方式:NSInvocationOperation、NSBlockOperation

二、NSInvocationOperation

  • 因為 NSOperation 沒有新增操作方法,所以 NSOperation 不能直接使用,使用 NSInvocationOperation、NSBlockOperation來建立:
  • NSInvocationOperation 建立步驟:
    • 1、將操作封裝到 Operation 中
    • 2、執行封裝的操作
    • 注意:如果直接執行 NSInvocationOperation 中的操作,那麼預設會在主執行緒中執行
    NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(demo) object:nil];
    [op1 start];

三、NSBlockOperation

  • 建立過程
    • 1、將操作封裝到Operation中
    • 2、新增操作
    • 注意:
      • 如果只封裝了一個操作,那麼預設會在主執行緒執行
      • 如果封裝了多個操作,那麼除了第一個操作以外,其他的操作會線上程執行
  //1、將操作封裝到Operation中
    NSBlockOperation*op = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1 - %@",[NSThread currentThread]);
    }];
    //2、新增操作
    //如果只封裝了一個操作,那麼預設會在主執行緒執行
    //如果封裝了多個操作,那麼除了第一個操作以外,其他的操作會在子執行緒執行
    [op addExecutionBlock:^{
          NSLog(@"2 - %@",[NSThread currentThread]);
    }];
    [op addExecutionBlock:^{
          NSLog(@"3 - %@",[NSThread currentThread]);
    }];

四、自定義Operation

  • 封裝的操作:
    • 如果是自定義類繼承與 NSOperation,那麼需要將操作寫到自定義類的 main 方法中
    • 這種實現方式,可以提高程式碼的複用性(可以將 block 中程式碼的實現寫在 main 函式內)
MitchellOperation*op = [[MitchellOperation alloc]init];
    [op start];
#import "MitchellOperation.h"
@implementation MitchellOperation
-(void)main{
//在這裡自定義耗時的操作
    NSLog(@"%s%@",__func__,[NSThread currentThread]);
}
@end

五、NSOperationQueue

  • 建立順序:
    • 封裝任務
    • 將任務新增到佇列
    • 注意:
      • 只要將任務新增到自己建立的佇列中,那麼佇列內部會自動呼叫 start 。
      • 只要將任務新增到佇列中,就會開啟一個新的執行緒執行佇列
      • 根據傳入的block,建立一個 NSBlockOperation 物件
      • 將建立好的 NSBlockOperation 物件,新增到佇列中
 1、建立佇列
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
 2、封裝任務
 2.1 NSInvocationOperation
    NSInvocationOperation*op1 =   [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(demo) object:nil];
 2.2 NSBlockOperation
    NSBlockOperation*op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"%@",[NSThread currentThread]);
    }];
 3、將任務新增到佇列
    [queue addOperation:op1];
    [queue addOperation:op2]; 

六、NSOperationQueue 的序列與併發

  • 預設是併發
  • 如果想實現序列,那麼設定 maxConcurrentOperationCount = 0
  • 注意:最大併發數,不能設定位0,否則任務不會被執行,如果想在主執行緒中執行任務,那麼直接建立 mainQueue 即可。

七、NSOperationQueue 暫停、恢復、取消

  • 暫停佇列中的任務
    • YES 需要暫停
    • NO 恢復執行
    • 注意:
      • 如果再任務執行的過程中暫停佇列的任務,那麼當前正在執行的任務並不會被暫停,而是會暫停佇列中的下一個任務。
      • 恢復任務,是從佇列第一個沒有被執行過的任務開始恢復。
    self.queue.suspended = !self.queue.suspended;

+取消任務:
- 注意:
* 取消任務和暫停任務一樣,不會取消當前正在執行的任務。
* 所以當執行耗時操作的時候,每執行一段程式碼之後就應該判斷一下當前操作是否被取消,可以節約效能。

    [self.queue cancelAllOperations];

八、NSOperationQueue 任務間的依賴和監聽

  • 依賴:
    [op2 addDependency:op1];
  • 監聽:
op1.completionBlock = ^(){
        NSLog(@"圖片1下載完畢");
    };
  • 例項
NSOperationQueue*queue = [[NSOperationQueue alloc]init];
    //下第一張圖片
    NSOperation*op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下載1");
    }];
    //下第二張圖片
    NSOperation*op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下載2");
    }];
    NSOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下載3");
        //回主執行緒渲染圖片
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            NSLog(@"渲染");
        }];
    }];
    //監聽任務是否執行完畢
    op1.completionBlock = ^(){
        NSLog(@"圖片1下載完畢");
    };
    op2.completionBlock = ^(){
        NSLog(@"圖片2下載完畢");
    };
    //新增依賴
    //只要新增了依賴,那麼就會等到依賴的任務執行完畢,才會執行當前任務
    //注意:
    //1、新增依賴,不能新增迴圈依賴
    //2、NSOperation可以跨佇列新增依賴
    [op2 addDependency:op1];
    [op3 addDependency:op2];
    [queue addOperation:op1];
    [queue addOperation:op2];
    [queue addOperation:op3];

相關文章