iOS 并發(fā)編程 - Operation And NSOperation Queue

  • 基本概念

    1. 術(shù)語(yǔ)
    2. 串行 vs 并發(fā)(concurrency)
    3. 同步 vs 異步
    4. 隊(duì)列 vs 線程
  • iOS的并發(fā)編程模型

  • Operation Queues vs. Grand Central Dispatch (GCD)

  • 關(guān)于Operation對(duì)象

    1. 并發(fā)的Operation 和非并發(fā)的Operation
    2. 創(chuàng)建NSBlockOperation對(duì)象
    3. 創(chuàng)建NSInvocationOperation對(duì)象
  • 自定義Operation對(duì)象

    1. 自定義的非并發(fā)NSOperation-不實(shí)現(xiàn)取消操作
    2. 自定義的非并發(fā)NSOperation-實(shí)現(xiàn)取消操作
  • 定制Operation對(duì)象的執(zhí)行行為

    1. 修改Operation在隊(duì)列中的優(yōu)先級(jí)
    2. 修改Operation執(zhí)行任務(wù)線程的優(yōu)先級(jí)
    3. 設(shè)置Completion Block
  • 執(zhí)行Operation對(duì)象

    1. 添加Operation到Operation Queue中
    2. 手動(dòng)執(zhí)行Operation
    3. 取消Operation
    4. 等待Operation執(zhí)行完成
    5. 暫停和恢復(fù)Operation Queue
  • 添加Operation Queue中Operation對(duì)象之間的依賴(lài)

  • 總結(jié)


看過(guò)上面的結(jié)構(gòu)預(yù)覽,下面就開(kāi)始我們這篇blog

術(shù)語(yǔ)

Operation: The NSOperation class is an abstract class you use to encapsulate the code and data associated with a single task.

解釋?zhuān)篛peration是一個(gè)抽象類(lèi)。你可以通過(guò)組織一段代碼和數(shù)據(jù),表示一個(gè)任務(wù)。

Operation Queue: The NSOperationQueue class regulates the execution of a set of NSOperation objects.

解釋?zhuān)?NSOperationQueue用于規(guī)則的去執(zhí)行一系列Operation。
任務(wù):通常的說(shuō)是由一段代碼和數(shù)據(jù)組成,可以完成特定某項(xiàng)功能的代碼數(shù)據(jù)集合。
進(jìn)程:進(jìn)程可以理解CPU所能執(zhí)行的單個(gè)任務(wù),CPU任何一個(gè)時(shí)刻職能運(yùn)行一個(gè)進(jìn)程。
線程:線程是計(jì)算機(jī)CPU所能執(zhí)行最小單元,亦可以理解簡(jiǎn)化版的進(jìn)程。一個(gè)進(jìn)程可以包含多個(gè)線程。

串行 vs 并發(fā)

最簡(jiǎn)單的理解就是,串行和并發(fā)是用來(lái)修飾是否可以同時(shí)執(zhí)行任務(wù)的數(shù)量的。串行設(shè)計(jì)只允許同一個(gè)時(shí)間段中只能一個(gè)任務(wù)在執(zhí)行。并發(fā)設(shè)計(jì)在同一個(gè)時(shí)間段中,允許多個(gè)任務(wù)在邏輯上交織進(jìn)行。(在iOS中,串行和并發(fā)一般用于描述隊(duì)列)
說(shuō)個(gè)題外話,剛開(kāi)始是將并發(fā)寫(xiě)成并行的,后覺(jué)得并發(fā)和并行的概念一直揮之不去,可以參考這篇,很贊奧——還在疑惑并發(fā)和并行?

同步 vs 異步

同步操作,只有當(dāng)該操作執(zhí)行完成返回后,才能執(zhí)行其他代碼,會(huì)出現(xiàn)等待,易造成線程阻塞。異步操作,不需要等到當(dāng)前操作執(zhí)行完,就可以返回,執(zhí)行其他代碼。(一般用于描述線程)

隊(duì)列 vs 線程

隊(duì)列用于存放Operation。在iOS中,隊(duì)列分為串行隊(duì)列和并發(fā)隊(duì)列。使用NSOperationQueue時(shí),我們不需要自己創(chuàng)建去創(chuàng)建線程,我們只需要自己去創(chuàng)建我們的任務(wù)(Operation),將Operation放到隊(duì)列中去。隊(duì)列會(huì)負(fù)責(zé)去創(chuàng)建線程執(zhí)行,執(zhí)行完后,會(huì)銷(xiāo)毀釋放線程占用的資源。


iOS并發(fā)編程模型

對(duì)于一個(gè)APP,需要提高應(yīng)用的性能,一般需要?jiǎng)?chuàng)建輔助的線程去執(zhí)行任務(wù)。在整個(gè)APP的生命周期內(nèi),我們需要自己手動(dòng)去創(chuàng)建,銷(xiāo)毀線程,以及暫停,開(kāi)啟線程。對(duì)于這創(chuàng)建一個(gè)這樣的線程管理方案,已經(jīng)是非常復(fù)雜且艱巨的任務(wù)。但是蘋(píng)果爸爸為開(kāi)發(fā)者提供了兩套更好的解決方案:NSOperationGrand Central Dispatch (GCD) Reference,GCD的方式具體的本文暫不討論。

使用NSOperationQueue 和 NSOperation的方式是蘋(píng)果基于GCD再一次封裝的一層,比GCD更加的靈活,而且是一種面向?qū)ο笤O(shè)計(jì),更加適合開(kāi)發(fā)人員。雖然相對(duì)于GCD會(huì)犧牲一些性能,但是我們可以對(duì)線程進(jìn)行更多的操作,比如暫停,取消,添加Operation間的依賴(lài)。但是GCD如果暫停和取消線程操作則十分的麻煩。

Operation Queues vs. Grand Central Dispatch (GCD)

簡(jiǎn)單來(lái)說(shuō),GCD 是蘋(píng)果基于 C 語(yǔ)言開(kāi)發(fā)的,一個(gè)用于多核編程的解決方案,主要用于優(yōu)化應(yīng)用程序以支持多核處理器以及其他對(duì)稱(chēng)多處理系統(tǒng)。而 Operation Queues 則是一個(gè)建立在 GCD 的基礎(chǔ)之上的,面向?qū)ο蟮慕鉀Q方案。它使用起來(lái)比 GCD 更加靈活,功能也更加強(qiáng)大。下面簡(jiǎn)單地介紹了 Operation Queues 和 GCD 各自的使用場(chǎng)景:

Operation Queues :相對(duì) GCD 來(lái)說(shuō),使用 Operation Queues 會(huì)增加一點(diǎn)點(diǎn)額外的開(kāi)銷(xiāo),但是我們卻換來(lái)了非常強(qiáng)大的靈活性和功能,我們可以給 operation 之間添加依賴(lài)關(guān)系、取消一個(gè)正在執(zhí)行的 operation 、暫停和恢復(fù) operation queue 等;
GCD :則是一種更輕量級(jí)的,以 FIFO 的順序執(zhí)行并發(fā)任務(wù)的方式,使用 GCD 時(shí)我們并不關(guān)心任務(wù)的 調(diào)度情況,而讓系統(tǒng)幫我們自動(dòng)處理。但是 GCD 的短板也是非常明顯的,比如我們想要給任務(wù)之間添加依賴(lài)關(guān)系、取消或者暫停一個(gè)正在執(zhí)行的任務(wù)時(shí)就會(huì)變得非常棘手。

上引用自Operation Queues vs. Grand Central Dispatch (GCD)

關(guān)于Operation對(duì)象

NSOperation對(duì)象是一個(gè)抽象類(lèi),是不能直接創(chuàng)建對(duì)象的。但是它有兩個(gè)子類(lèi)——NSBlockOperationNSInvocationOperation.通常情況下我們都可以直接使用這兩個(gè)子類(lèi),創(chuàng)建可以并發(fā)的任務(wù)。

我們查看關(guān)于NSOperation.h的頭文件,可以發(fā)現(xiàn)任意的operation對(duì)象都可以自行開(kāi)始任務(wù)(start),取消任務(wù)(cancle),以及添加依賴(lài)(addDependency:)和移除依賴(lài)(removeDependency:).關(guān)于依賴(lài),有一種很好的一種開(kāi)發(fā)思路。在operation對(duì)象中有很多屬性,可以用于檢測(cè)當(dāng)前任務(wù)的狀態(tài),如isCancelled:是否已經(jīng)取消,isFinished:是否已經(jīng)完成了任務(wù)。

屏幕快照 2016-06-07 下午8.29.04.png

  • 創(chuàng)建NSBlockOperation

以下使用到的代碼片段取自我的LSOperationAndOperationQueueDemo

NSBlockOperation顧名思義,是是用block來(lái)創(chuàng)建任務(wù),主要有兩種方式創(chuàng)建,一種是是用類(lèi)方法,一種是創(chuàng)建operation對(duì)象,再添加任務(wù)。上代碼:以下代碼包括了兩種block創(chuàng)建任務(wù)的方式。以及已經(jīng)有任務(wù)的operation對(duì)象再添加任務(wù)。及直接添加任務(wù)到queue中。

@implementation LSBlockOperation

+ (LSBlockOperation *)lsBlockOperation {
    return [[LSBlockOperation alloc] init];
}

- (void)operatingLSBlockOperation {
    
    NSBlockOperation *blockOpt1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"-------- blockOpt1, mainThread:%@, currentThread:%@", [NSThread mainThread], [NSThread currentThread]);
    }];
    /// 繼續(xù)添加執(zhí)行的block
    [blockOpt1 addExecutionBlock:^{
        NSLog(@"-------- blockOpt1 addExecutionBlock1 mainThread:%@, currentThread:%@", [NSThread mainThread], [NSThread currentThread]);
    }];
    
    [blockOpt1 addExecutionBlock:^{
        NSLog(@"-------- blockOpt1 addExecutionBlock2 mainThread:%@, currentThread:%@", [NSThread mainThread], [NSThread currentThread]);
    }];
    
    NSBlockOperation *blockOpt2 = [[NSBlockOperation alloc] init];
    [blockOpt2 addExecutionBlock:^{
        NSLog(@"-------- blockOpt2 mainThread:%@, currentThread:%@", [NSThread mainThread], [NSThread currentThread]);
    }];
    
    NSBlockOperation *blockOpt3 = [[NSBlockOperation alloc] init];
    [blockOpt3 addExecutionBlock:^{
        NSLog(@"-------- blockOpt3 mainThread:%@, currentThread:%@", [NSThread mainThread], [NSThread currentThread]);
    }];
    
    NSBlockOperation *blockOpt4 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"-------- blockOpt4 mainThread:%@, currentThread:%@", [NSThread mainThread], [NSThread currentThread]);
    }];
    
    // 添加執(zhí)行優(yōu)先級(jí) - 并不能保證執(zhí)行順序
//    blockOpt2.queuePriority = NSOperationQueuePriorityVeryHigh;
//    blockOpt4.queuePriority = NSOperationQueuePriorityHigh;
    
    /// 可以設(shè)置Operation之間的依賴(lài)關(guān)系 - 執(zhí)行順序3 2 1 4
    [blockOpt2 addDependency:blockOpt3];
    [blockOpt1 addDependency:blockOpt2];
    [blockOpt4 addDependency:blockOpt1];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation:blockOpt1];
    [queue addOperation:blockOpt2];
    [queue addOperation:blockOpt3];
    [queue addOperation:blockOpt4];
    [queue addOperationWithBlock:^{
        NSLog(@"-------- queue addOperationWithBlock1 mainThread:%@, currentThread:%@", [NSThread mainThread], [NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"-------- queue addOperationWithBlock2 mainThread:%@, currentThread:%@", [NSThread mainThread], [NSThread currentThread]);
    }];
}
  • 創(chuàng)建NSInvocationOperation

NSInvocationOperation是另一種可創(chuàng)建的operation對(duì)象的類(lèi)。但是在Swift中已經(jīng)被去掉了。NSInvocationOperation是一種可以非常靈活的創(chuàng)建任務(wù)的方式,主要是其中包含了一個(gè)targetselector。假設(shè)我們現(xiàn)在有一個(gè)任務(wù),已經(jīng)在其它的類(lèi)中寫(xiě)好了,為了避免代碼的重復(fù),我們可以將當(dāng)前的target指向?yàn)槟莻€(gè)類(lèi)對(duì)象,方法選擇器指定為那個(gè)方法即可,如果有參數(shù),可以在NSInvocationOperation創(chuàng)建中指定對(duì)應(yīng)的Object(參數(shù)).

具體的可以看如下代碼:LSOperationAndOperationQueueDemo

@implementation LSInvocationOperation

+ (LSInvocationOperation *)lsInvocationOperation {
    return [[LSInvocationOperation alloc] init];
}

- (void)operationInvocationOperation {
    
    NSInvocationOperation *invoOpt1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invoOperated1) object:self];
    NSInvocationOperation *invoOpt2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invoOperated2) object:self];
    
    // invocated other obj method
    /// 可以執(zhí)行其它類(lèi)中方法,并且可以帶參數(shù)
    NSInvocationOperation *invoOpt4 = [[NSInvocationOperation alloc] initWithTarget:[[Person alloc] init] selector:@selector(running:) object:@"linsir"];
    
    // 設(shè)置優(yōu)先級(jí) - 并不能保證按指定順序執(zhí)行
//    invoOpt1.queuePriority = NSOperationQueuePriorityVeryLow;
//    invoOpt4.queuePriority = NSOperationQueuePriorityVeryLow;
//    invoOpt2.queuePriority = NSOperationQueuePriorityHigh;
    
    // 設(shè)置依賴(lài) - 線性執(zhí)行
    [invoOpt1 addDependency:invoOpt2];
    [invoOpt2 addDependency:invoOpt4];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation:invoOpt1];
    [queue addOperation:invoOpt2];
    [queue addOperation:invoOpt4];
}

- (void)invoOperated1 {
    NSLog(@"--------- invoOperated1, mainThread:%@, currentThread:%@", [NSThread mainThread],[NSThread currentThread]);
}

- (void)invoOperated2 {
    NSLog(@"--------- invoOperated2, mainThread:%@, currentThread:%@", [NSThread mainThread],[NSThread currentThread]);
}

@end

自定義Operation對(duì)象

上文介紹了兩種系統(tǒng)定義的NSOperation,通常情況下,我們可以直接使用,已經(jīng)可以滿足了大部分的需求。但是當(dāng)系統(tǒng)的不能滿足時(shí)候,我們就需要自定義我們自己的Operation對(duì)象。Operation對(duì)象可以分為并發(fā)的和非并發(fā)的兩類(lèi)。從實(shí)現(xiàn)角度上而言,非并發(fā)的更容易實(shí)現(xiàn)的多。因?yàn)榉遣l(fā)的Operation對(duì)象中的很多屬性,它的父類(lèi)已經(jīng)做好了管理,我們只需要直接使用就可以了。(通常情況下,實(shí)現(xiàn)多線程是由NSOperationQueue對(duì)象管理的,而不是NSOperation對(duì)象)實(shí)現(xiàn)自定義的NSOperation對(duì)象,最少需要重寫(xiě)兩個(gè)方法,一個(gè)是初始化init方法(傳值),一個(gè)是mian方法(主要的邏輯實(shí)現(xiàn))。

  • 自定義的非并發(fā)NSOperation-不實(shí)現(xiàn)取消操作

    代碼片段取自LSOperationAndOperationQueueDemo

      @interface LSNonConcurrentOperation ()
    
      @property (nonatomic, strong)id data;
      
      @end
      
      /**
       自定義一個(gè)非并發(fā)的Operation,最少需要實(shí)現(xiàn)兩個(gè)方法,一個(gè)初始化的init方法,另一個(gè)是mian方法,即主方法,邏輯的主要執(zhí)行體。
       */
      @implementation LSNonConcurrentOperation
      
      - (id)initWithData:(id)data {
          self = [self init];
          if (self) {
              self.data = data;
          }
          return self;
      }
      
      // 該主方法不支持Operation的取消操作
      - (void)main {
          @try {
              
              NSLog(@"-------- LSNonConcurrentOperation - data:%@, mainThread:%@, currentThread:%@", self.data, [NSThread mainThread], [NSThread currentThread]);
              sleep(2);
              NSLog(@"-------- finish executed %@", NSStringFromSelector(_cmd));
              
          } @catch (NSException *exception) {
              
              NSLog(@"------- LSNonConcurrentOperation exception - %@", exception);
              
          } @finally {
              
          }
      }
    
  • 自定義的非并發(fā)NSOperation-實(shí)現(xiàn)取消操作

      - (void)main {
          // 執(zhí)行之前,檢查是否取消Operation
          if (self.isCancelled) return;
      
          @try {
              NSLog(@"-------- LSNonConcurrentOperation - data:%@, mainThread:%@, currentThread:%@", self.data, [NSThread mainThread], [NSThread currentThread]);
              
              // 循環(huán)去檢測(cè)執(zhí)行邏輯過(guò)程中是否取消當(dāng)前正在執(zhí)行的Operation
              for (NSInteger i = 0; i < 10000; i++) {
                  
                  NSLog(@"run loop -- %@", @(i + 1));
                  
                  if (self.isCancelled) return;
                  sleep(1);
              }
              NSLog(@"-------- finish executed %@", NSStringFromSelector(_cmd));
          } @catch (NSException *exception) {
              NSLog(@"------- LSNonConcurrentOperation exception - %@", exception);
              
          } @finally {
              
          }
      }
    

由上可以知道,取消一個(gè)任務(wù)的執(zhí)行,其實(shí)并不是立即就會(huì)取消,而是會(huì)在一個(gè)runloop中不斷的去檢查,判斷isCancle的值,直到為yes時(shí)候,則取消了操作。所以,設(shè)置Operation為cancle的時(shí)候,至少需要一個(gè)runloop的時(shí)間才會(huì)結(jié)束操作。

定制Operation對(duì)象的執(zhí)行行為

  • 修改Operation在隊(duì)列中的優(yōu)先級(jí)

NSOperation對(duì)象在Queue中可以設(shè)置執(zhí)行任務(wù)的優(yōu)先級(jí)。我們可以通過(guò)設(shè)置operation對(duì)象的setQueuePriority:方法,改變?nèi)蝿?wù)在隊(duì)列中的執(zhí)行優(yōu)先級(jí)。但是真正決定一個(gè)operation對(duì)象能否執(zhí)行的是isReady,假設(shè)一個(gè)operation對(duì)象的在隊(duì)列執(zhí)行的優(yōu)先級(jí)很高,另一個(gè)很低,但是高的operation對(duì)象的isReady是NO,也只會(huì)執(zhí)行優(yōu)先級(jí)低的operation任務(wù)。另一個(gè)影響任務(wù)在隊(duì)列中執(zhí)行順序的是依賴(lài)(下文會(huì)講到),假設(shè)operation A依賴(lài)于operation B,所以一定先執(zhí)行operation B,再執(zhí)行operation A.

  • 修改Operation執(zhí)行任務(wù)線程的優(yōu)先級(jí)

從iOS4.0開(kāi)始,我們可以設(shè)置operation中任務(wù)執(zhí)行的線程優(yōu)先級(jí)。從iOS4.0到iOS8.0,operation對(duì)象可以通過(guò)方法setThreadPriority:,這里的參數(shù)是一個(gè)double類(lèi)型,范圍是0.0到1.0,設(shè)置越高,理論上講,線程執(zhí)行的可能性就越高。但是從iOS8.0之后,這個(gè)方法已經(jīng)被廢棄了,使用setQualityOfService:代替,這里參數(shù)是一個(gè)預(yù)設(shè)的枚舉值。

  • 設(shè)置Completion Block

同上,從iOS4.0開(kāi)始,可以給每個(gè)operation對(duì)象設(shè)置一個(gè)主任務(wù)完成之后的完成回調(diào)setCompletionBlock:。所設(shè)置的block執(zhí)行是在檢測(cè)到operation的isFinished為YES后執(zhí)行的。值得注意的是:我們并不能保證block所在的線程一定在主線程,所以當(dāng)我們需要對(duì)主線程上做一些操作的時(shí)候,我們應(yīng)該切換線程到主線程中,如需在其他線程執(zhí)行的某些操作,亦需要切換線程。

Therefore, you should not use this block to do any work that requires a very specific execution context. Instead, you should shunt that work to your application’s main thread or to the specific thread that is capable of doing it.

執(zhí)行Operation對(duì)象

對(duì)于執(zhí)行一個(gè)Operation對(duì)象,一般的做法是將operation對(duì)象添加到一個(gè)隊(duì)列中去,之后隊(duì)列會(huì)根據(jù)當(dāng)前系統(tǒng)的狀態(tài),以及內(nèi)核的狀態(tài),自行的去執(zhí)行operation中的任務(wù)。

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:opt];

還有一種做法是,我們可以手動(dòng)的執(zhí)行一個(gè)operation對(duì)象,直接調(diào)用operation的start方法

[opt start];
  • 添加Operation到Operation Queue中

將operation對(duì)象添加到queue中非常簡(jiǎn)單

首先創(chuàng)建一個(gè)隊(duì)列:

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

添加到隊(duì)列的方法如下:

- (void)addOperation:(NSOperation *)op;
- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait NS_AVAILABLE(10_6, 4_0);
- (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);

第一個(gè):添加意境存在的operation對(duì)象
第二個(gè):添加一組operation對(duì)象
第三個(gè):直接添加一個(gè)block到隊(duì)列中,無(wú)需創(chuàng)建operation對(duì)象

  • 手動(dòng)執(zhí)行Operation

一般情況下,我們不需要手動(dòng)的去執(zhí)行一個(gè)operation對(duì)象,但如果需要,亦可,調(diào)用start方法。

[opt start];
  • 取消Operation

當(dāng)我們將一個(gè)operation對(duì)象添加到隊(duì)列中之后,operation就已經(jīng)被隊(duì)列所擁有。我們可以在某個(gè)需要的時(shí)候調(diào)用operation對(duì)象的cancle方法,將operation出列。并且此時(shí)operation的isFinished也會(huì)為YES,所以此時(shí)依賴(lài)于它的operation就回繼續(xù)得到執(zhí)行。當(dāng)然,我們可以直接調(diào)用隊(duì)列的cancelAllOperations方法,取消了隊(duì)列中所有的operation執(zhí)行。

  • 等待Operation執(zhí)行完成

等待一個(gè)Operation對(duì)象的執(zhí)行完成,可以使用waitUntilFinished方法。但是應(yīng)該注意到,等待一個(gè)任務(wù)執(zhí)行完,會(huì)阻塞當(dāng)前線程。所以我們絕不應(yīng)該在主線程中做該操作,那樣會(huì)帶來(lái)非常差的體驗(yàn)。所以該操作應(yīng)該使用輔助線程中。
我們也可以調(diào)用NSOperationQueue對(duì)象的waitUntilAllOperationsAreFinished方法,知道所有的任務(wù)都執(zhí)行完成。

  • 暫停和恢復(fù)Operation Queue

通過(guò)設(shè)置隊(duì)列的setSuspended,我們可以暫停一個(gè)隊(duì)列中還沒(méi)有開(kāi)始執(zhí)行的operation對(duì)象,對(duì)于已經(jīng)開(kāi)始的執(zhí)行的任務(wù),將繼續(xù)執(zhí)行。并且,已經(jīng)暫停了隊(duì)列,仍然可以繼續(xù)添加operation對(duì)象,但是不會(huì)執(zhí)行,只能等到從暫停(掛起)狀態(tài)切換到非暫停狀態(tài)。即設(shè)置setSuspended為NO。對(duì)于單個(gè)的operation,是沒(méi)有暫停的概念的。

When the value of this property is NO, the queue actively starts operations that are in the queue and ready to execute. Setting this property to YES prevents the queue from starting any queued operations, but already executing operations continue to execute. You may continue to add operations to a queue that is suspended but those operations are not scheduled for execution until you change this property to NO.

添加Operation Queue中Operation對(duì)象之間的依賴(lài)

NSOperationQueue中,如果沒(méi)有經(jīng)過(guò)對(duì)operation添加依賴(lài),都是使用并發(fā)處理的。但是在某些情況下,我們對(duì)任務(wù)的執(zhí)行是有非常嚴(yán)格的規(guī)定的。即需要串行執(zhí)行,此時(shí),我們就需要對(duì)operation對(duì)象間進(jìn)行添加依賴(lài)處理。

- (void)addDependency:(NSOperation *)op;
- (void)removeDependency:(NSOperation *)op;

第一個(gè):添加依賴(lài)
第二個(gè):移除依賴(lài)

依賴(lài),是一種非常好用功能,在我們做項(xiàng)目(生活中)的時(shí)候,很多時(shí)候都一種依賴(lài)的概念。比如,用戶(hù)需要上傳一張照片到自己的空間,但是此時(shí)必須檢測(cè)該用戶(hù)是否已經(jīng)登錄。以前我們可能將兩個(gè)邏輯寫(xiě)在一起,但是現(xiàn)在可以將成寫(xiě)成兩個(gè)不同的operation,并設(shè)置它們的依賴(lài)。這樣的好處非常可見(jiàn)的:
第一點(diǎn):它可以幫我們解藕,不同的邏輯分在不一樣的對(duì)象中。
第二點(diǎn):某些常用的邏輯會(huì)經(jīng)常用到,以后不需要一次次的重復(fù),可讀性增強(qiáng),以后需要的時(shí)候直接調(diào)用,設(shè)置其依賴(lài)即可。比如檢測(cè)是否登錄

總結(jié)

多線程執(zhí)行任務(wù)看似十分的復(fù)雜,但是如果將復(fù)雜的任務(wù)交給NSOperation and NSOperationQueue,就可以簡(jiǎn)化它的難度,并且它似乎可以比我們自己處理的更好。

文中使用的demo - LSOperationAndOperationQueueDemo

感謝

以下文章給我?guī)?lái)非常大的幫助

還在疑惑并發(fā)和并行?
進(jìn)程與線程的一個(gè)簡(jiǎn)單解釋
iOS 并發(fā)編程之 Operation Queues
NSOperationQueue - 文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容