天天看點

iOS NSoperation

文章目錄
    一、NSOperation簡介
    二、NSOperation和NSOperationQueue的基本使用
        1、建立任務
        2、建立隊列
        3、将任務加入到隊列中
    三、控制串行執行和并行執行的關鍵
    四、操作依賴
    五、一些其他方法
           

一、NSoperation的簡介

NSOperation是蘋果提供給我們的一套多線程解決方案。實際上NSOperation是基于GCD更高一層的封裝,但是比GCD更簡單易用、代碼可讀性也更高。

NSoperation 總共有兩個子類 : NSInvocationOperation 和 NSBlockOperation。

NSOperation需要配合NSOperationQueue來實作多線程。因為預設情況下,NSOperation單獨使用時系統同步執行操作,并沒有開辟新線程的能力,隻有配合NSOperationQueue才能實作異步執行。

因為NSOperation是基于GCD的,那麼使用起來也和GCD差不多,其中,NSOperation相當于GCD中的任務,而NSOperationQueue則相當于GCD中的隊列。NSOperation實作多線程的使用步驟分為三步:

1、建立任務:先将需要執行的操作封裝到一個NSOperation對象中。

2、建立隊列:建立NSOperationQueue對象。

3、将任務加入到隊列中:然後将NSOperation對象添加到NSOperationQueue中。

之後呢,系統就會自動将NSOperationQueue中的NSOperation取出來,在新線程中執行操作。

注意和GCD 類比學習 : Operation 相當于任務、操作隊列就和GCD其實是同個意思。總歸來說,NSOperation 比GCD 更有自主性!例如: 可以通過繼承重寫main方法自定義任務、可暫停任務、可恢複任務、可通過KVO監Operation是否完成或取消,可設定任務權重優先執行任務、可設定等待等

下面我們來學習下NSOperation和NSOperationQueue的基本使用。

二、NSOperation和NSOperationQueue的基本使用

NSOperation是個抽象類,并不能封裝任務。我們隻有使用它的子類來封裝任務。我們有三種方式來封裝任務:

1、使用 NSInvocationOperation

2、使用 NSBlockOperation

3、自定義子類繼承NSoperation,并重寫main方法

1、在不使用NSOperationQueue,單獨使用NSOperation的情況下系統同步執行操作,下面我們學習以下任務的三種建立方式。

1 ) 使用 NSInvocationOperation

NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run) object:nil];

  // 調用start 方法執行操作
 [operation start];


//其中run方法的定義如下
- (void)run
{
    NSLog(@"NSInvocationOperation -> 目前線程:%@", [NSThread currentThread]);   
}
           

運作結果 :

iOS NSoperation

說明 :從中可以看到,在沒有使用隊列(NSOperationQueue),單獨使用NSInvocationOperation的情況下,NSInvocationOperation在主線程執行操作,并沒有開啟新線程。

.

.

.

2 ) 使用 NSBlockOperation

NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"NSBlockOperation -> 目前線程:%@", [NSThread currentThread]);

    }]; 
    //  NSBlockOperation 提供 addExecutionBlock,可通過這個進行添加額外的操作,這些額外操作在有可能在主線程中執行,也有可能會開啟子線程去執行。
    [blockOperation addExecutionBlock:^{

        NSLog(@"NSBlockOperation 額外操作任務1:%@", [NSThread currentThread]);

    }];

    [blockOperation addExecutionBlock:^{

        NSLog(@"NSBlockOperation 額外操作任務2:%@", [NSThread currentThread]);

    }];

    [blockOperation addExecutionBlock:^{

        NSLog(@"NSBlockOperation 額外操作任務3:%@", [NSThread currentThread]);

    }];

    [blockOperation start];
           

運作結果 :

iOS NSoperation

說明 :

<1> 在沒有使用NSOperationQueue、單獨使用NSBlockOperation的情況下,NSBlockOperation也是在主線程執行操作,并沒有開啟新線程

<2> NSBlockOperation 提供 addExecutionBlock,可通過這個進行添加額外的操作,這些額外操作在有可能在主線程中執行,也有可能會開啟子線程去執行

.

.

.

3 ) 自定義子類繼承NSoperation,并重寫main方法

先定義一個繼承自NSOperation的子類,重寫main方法

CustomOperation.h

#import <Foundation/Foundation.h>

@interface CustomOperation : NSOperation

@end
           

CustomOperation.m

#import "CustomOperation.h"  
@implementation CustomOperation

- (void)main
{
    for (int i = ; i < ; i++) {

        NSLog(@"定義繼承自NSOperation的子類封裝任務:%@",[NSThread currentThread]);

    }

}

@end
           

導入頭檔案 CustomOperation.h

CustomOperation *customOperation = [[CustomOperation alloc]init];
 [customOperation start];
           

運作結果 :

iOS NSoperation

說明 : 在沒有使用NSOperationQueue、單獨使用自定義子類的情況下,是在主線程執行操作,并沒有開啟新線程。

2、建立隊列

和GCD中的并發隊列、串行隊列略有不同的是:NSOperationQueue一共有兩種隊列:主隊列、其他隊列。其中其他隊列同時包含了串行、并發功能。下邊是主隊列、其他隊列的基本建立方法和特點。

 主隊列

凡是添加到主隊列的任務,必然是放在主線程中執行

 其它隊列

添加到這種隊列中的任務(NSOperation),就會自動放到子線程中執行,同時包含了:串行、并發功能

3、将任務添加到隊列中去

// 1、 建立 隊列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];

// 2、定義任務
NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run) object:nil];


NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
         for (int i = ; i < ; i++) {
            NSLog(@"NSBlockOperation任務:%@",[NSThread currentThread]);


        }

    }];

// 3、 将任務添加到隊列中
[queue addOperation:invocationOperation];
[queue addOperation:blockOperation];
           

運作結果 :

iOS NSoperation

說明 :NSInvocationOperation和NSOperationQueue結合後能夠開啟新線程,進行并發執行NSBlockOperation和NSOperationQueue也能夠開啟新線程,進行并發執行。

當然,你也可以無需先建立任務,可以在block中添加任務,直接将block中的人添加到隊列中。

[queue addOperationWithBlock:^{

        for (int i = ; i < ; i++) {

            NSLog(@"任務:%@",[NSThread currentThread]);

        }

    }];
           

運作結果 :

iOS NSoperation

.

.

.

三、控制串行執行和并行執行的關鍵

之前我們說過,NSOperationQueue建立的其他隊列同時具有串行、并發功能,上邊我們示範了并發功能,那麼他的串行功能是如何實作的?

這裡有個關鍵參數maxConcurrentOperationCount,這個官方的解釋是如下

The maximum number of queued operations that can execute at the same time.
           

中文可譯為 : 可以同時執行的隊列操作的最大數量

 maxConcurrentOperationCount 預設值為-1,表示不進行限制,預設為并發執行

 當 maxConcurrentOperationCount = 1,串行執行任務

 當maxConcurrentOperationCount大于1時,進行并發執行,當然這個值不應超過系統限制,即使自己設定一個很大的值,系統也會自動調整。

注意 : 這個參數主要控制隊列是串行執行任務還是并行執行任務,具體開啟的線程數交由系統控制。

具體看下面一個例子 :

// 建立隊列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

     //queue.maxConcurrentOperationCount = -1;
    queue.maxConcurrentOperationCount = ;

    // 添加操作
    [queue addOperationWithBlock:^{
        NSLog(@"1-----%@", [NSThread currentThread]);

    }];
    [queue addOperationWithBlock:^{
        NSLog(@"2-----%@", [NSThread currentThread]);

    }];
    [queue addOperationWithBlock:^{
        NSLog(@"3-----%@", [NSThread currentThread]);

    }];
           

當 maxConcurrentOperationCount = -1 時控制台輸出

iOS NSoperation

當 maxConcurrentOperationCount = 1 時控制台輸出

iOS NSoperation

可以看出:當最大并發數為1時,任務是按順序串行執行的。當最大并發數為2時,任務是并發執行的。而且開啟線程數量是由系統決定的,不需要我們來管理。這樣看來,是不是比GCD還要簡單了許多?

四、設定操作依賴

NSOperation和NSOperationQueue最吸引人的地方是它能添加操作之間的依賴關系。比如說有A、B兩個操作,其中A執行完操作,B才能執行操作,那麼就需要讓B依賴于A。具體如下:

- (void)addOperationDepedency
{
    // 1、 建立隊列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    // 2、 建立任務
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1-----%@", [NSThread  currentThread]);
    }];
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"2-----%@", [NSThread  currentThread]);
    }];


   //讓op2 依賴于 op1,則先執行op1,在執行op2
    [op2 addDependency:op1];    

    // 3、 将任務添加到隊列中
    [queue addOperation:op2];
    [queue addOperation:op1];


}//添加操作依賴
           

運作結果 :

iOS NSoperation

.

.

.

五、一些其他方法

 NSOperation提供的方法,可取消單個操作

- (void)cancel;

 NSOperationQueue提供的方法,可以取消隊列的所有操作

- (void)cancelAllOperations;

 可設定任務的暫停和恢複,YES代表暫停隊列,NO代表恢複隊列

- (void)setSuspended:(BOOL)b;

 判斷暫停狀态

- (BOOL)isSuspended;

注意:
    這裡的暫停和取消并不代表可以将目前的操作立即取消,而是當目前的操作執行完畢之後不再執行新的操作。
    暫停和取消的差別就在于:暫停操作之後還可以恢複操作,繼續向下執行;而取消操作之後,所有的操作就清空了,無法再接着執行剩下的操作。
           

相關連結 :

本文Demo傳送門

GCD和NSOperation的差別和選用