認識和使用NSOperation

NSOperation是OC中多線程技術(shù)的一種,是對GCD的OC包裝.它包含隊列(NSOperationQueue)操作(NSOperation)兩個基本要素.

通過這篇文章你可以了解到:

  • 怎樣使用NSOperation
  • 怎樣使用NSOperationQueue
  • 如何給NSOperationQueue設(shè)置并發(fā)數(shù)
  • NSOperationQueue的暫停恢復(fù)和取消
  • 通過添加依賴影響操作的執(zhí)行順序
  • NSOperation的進程間通信

怎樣使用NSOperation

  • NSOperation本身是一個抽象類,要使用可以通過以下幾個辦法:
    • 使用NSInvocationOperation
    • 使用NSBlockOperation
    • 自定義NSOperation的子類

使用

  • NSInvocationOperation
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task) object:nil];
// 調(diào)用start方法執(zhí)行操作op操作
[op start];
  • NSBlockOperation
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"task0---%@", [NSThread currentThread]);
}];
[op start];

根據(jù)打印的結(jié)果我們會發(fā)現(xiàn),直接調(diào)用start方法時,系統(tǒng)并不會開辟一個新的線程去執(zhí)行任務(wù),任務(wù)會在當(dāng)前線程同步執(zhí)行.

注意: 這里我們說的是當(dāng)前線程而非主線程,意即:如果是在主線程中調(diào)用op的start方法,那么該任務(wù)是在主線程中執(zhí)行;但如果是在其他子線程調(diào)用start方法,任務(wù)則是在其他子線程執(zhí)行.

當(dāng)然NSBlockOperation還有一種使用方法addExecutionBlock:使得我們可以給其添加更多的操作,使用如下:

NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"task0---%@", [NSThread currentThread]);
}];

[op addExecutionBlock:^{
    NSLog(@"task1----%@", [NSThread currentThread]);
}];

[op addExecutionBlock:^{
    NSLog(@"task2----%@", [NSThread currentThread]);
}];

// 開始必須在添加其他操作之后
[op start];

由打印的結(jié)果發(fā)現(xiàn): task0的結(jié)果和前面的結(jié)論一樣,是執(zhí)行在主線程中的(因為是在主線程中調(diào)用start方法),但task1和task2都是在自己的新線程中執(zhí)行.也就是說:當(dāng)NSBlockOperation封裝的操作數(shù)大于1的時候,就會執(zhí)行異步操作.

  • 自定義NSOperation

自定義NSOperation的方法也很簡單,我們需要做到下面幾個步驟:

1.子類化NSOperation

2.在.m文件里面實現(xiàn)-(void)main方法

3.初始化該操作的時候直接調(diào)用alloc及init即可

4.同樣可以通過start方法讓你自定義的任務(wù)跑在當(dāng)前線程中

關(guān)鍵代碼:

自定義NSOperation的實現(xiàn)文件:

#import "AROperation.h"
@implementation AROperation
- (void)main {
    NSLog(@"this is my custom operation ---- %@", [NSThread currentThread]);
}
@end

使用(在任何需要啟用該任務(wù)的地方):

// 該操作被執(zhí)行時就會執(zhí)行op內(nèi)部定義的任務(wù)
AROperation *op = [[AROperation alloc] init];
[op start];

怎樣使用NSOperationQueue

NSOperation的start方法默認是同步執(zhí)行任務(wù),這樣的使用并不多見,只有將NSOperation與NSOperationQueue進行結(jié)合,才會發(fā)揮出這種多線程技術(shù)的最大功效.當(dāng)NSOperation被添加到NSOperationQueue中后,就會全自動地執(zhí)行異步操作.

  • NSOperationQueue的種類:

    • 自帶主隊列[NSOperationQueue mainQueue]: 添加到主隊列中的任務(wù)都會在主線程中執(zhí)行
    • 自己創(chuàng)建隊列(非主隊列)
      NSOperationQueue *queue = [[NSOperationQueue alloc] init];: 這種隊列同時包含串行、并發(fā)的功能,添加到非主隊列的任務(wù)會自動放到子線程中執(zhí)行
  • 向NSOperationQueue中添加操作:

    • 直接添加
      [queue addOperation:op1];
    • 使用block添加,block的內(nèi)容會被包裝成operation對象添加到隊列
      [queue addOperationWithBlock:^{ }];
      操作一但被到添加到隊列中,就會自動異步執(zhí)行.

設(shè)置NSOperationQueue的最大并發(fā)數(shù)

NSOperationQueue可以通過以下方法設(shè)置最大并發(fā)數(shù),
setMaxConcurrentOperationCount:,值得注意的是:**當(dāng)并發(fā)數(shù)為1就變成了串行執(zhí)行任務(wù)
**

NSOperationQueue的暫停恢復(fù)和取消

  • 取消
    • NSOperation有一個cancel方法可以取消單個操作
    • NSOperationQueue的cancelAllOperations相當(dāng)于隊列中的每個operation調(diào)用了cancel方法,會取消隊列里面全部的操作.
    • 但是,不能取消正在進行中的任務(wù),隊列調(diào)用了cancelAllOperations后會等當(dāng)前正在進行的任務(wù)執(zhí)行完閉后取消后面的操作
  • 掛起和恢復(fù)
    • isSuspended : 判斷是否掛起
    • setSuspended: YES表示掛起,NO表示恢復(fù)
    • 和取消功能類似,我們同樣不能掛起正在運行中的操作,隊列會等當(dāng)前操作結(jié)束后將后面的操作暫停(掛起)

因此, 我們在自定義NSOperation的時候需要注意,最好可以經(jīng)常通過判斷isCancelled方法檢測操作是否被取消,以響應(yīng)外部可能進行的取消操作.如:

// 自定義NSOperation類.m文件的main方法實現(xiàn)
- (void)main {
    for (NSInteger i = 0; i < 1000; i++) {
        NSLog(@"SubTask---0---%zd",i);
    }
    // 判斷當(dāng)前任務(wù)是否被取消,如果已經(jīng)取消,及時返回
    if (self.cancelled) {
        return;
    }

    for (NSInteger i = 0; i < 1000; i++) {

        NSLog(@"SubTask---1---%zd", i);
    }
    if (self.cancelled) {
        return;
    }

    for (NSInteger i = 0; i < 1000; i++) {
        NSLog(@"SubTask---2---%zd",i);
    }
}

添加依賴和監(jiān)聽

  • 通過設(shè)置操作間的依賴,可以確定這些操作的執(zhí)行順序
    如:
[op3 addDependency:op1];
[op3 addDependency:op2];

表示op3會在op1和op2都執(zhí)行完畢后才執(zhí)行

添加依賴的時候要注意防止添加循環(huán)依賴,此外我們還可以在不同隊列的operation之間添加依賴

  • 監(jiān)聽
    • op.completeBlock可以監(jiān)聽一個操作執(zhí)行完畢的時刻,這個block里面可以添加一些我們需要執(zhí)行的操作
    • 這個block里面的操作仍然是在子線程執(zhí)行,但不一定和被監(jiān)聽的操作在同一個線程

線程間通信

有時我們在子線程中執(zhí)行完一些操作的時候,需要回到主線程做一些事情(如進行UI操作),因此需要從當(dāng)前線程回到主線程,以下載并顯示圖片為例,方法如下:

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 子線程下載圖片
[queue addOperationWithBlock:^{
    NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
    NSData *data = [NSData dataWithContentsOfURL:url];
    UIImage *image = [[UIImage alloc] initWithData:data];
    // 回到主線程進行顯示
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        self.imageView.image = image;
    }];
}];

NSOperation的使用還是比較簡單的,但是要注意的細節(jié)比較多,一些方法比較容易被忽略,于是乎特此總結(jié)一下.這里就不上傳示例代碼了,有問題的童鞋可以直接留言.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容