iOS多線程(三) --- > NSOperation的理解與使用

(一):NSOperation簡(jiǎn)介

NSOperation是基于GCD之上的更高一層封裝,NSOperation需要配合NSOperationQueue來實(shí)現(xiàn)多線程。

NSOperation實(shí)現(xiàn)多線程的步驟如下:

1. 創(chuàng)建任務(wù):先將需要執(zhí)行的操作封裝到NSOperation對(duì)象中。
2. 創(chuàng)建隊(duì)列:創(chuàng)建NSOperationQueue。
3. 將任務(wù)加入到隊(duì)列中:將NSOperation對(duì)象添加到NSOperationQueue中。

需要注意的是,NSOperation是個(gè)抽象類,實(shí)際運(yùn)用時(shí)中需要使用它的子類,有三種方式:

  1. 使用子類NSInvocationOperation
  2. 使用子類NSBlockOperation
  3. 定義繼承自NSOperation的子類,通過實(shí)現(xiàn)內(nèi)部相應(yīng)的方法來封裝任務(wù)。

(二):NSOperation的三種創(chuàng)建方式

1. NSBlockOperation的使用

把任務(wù)放到NSBlockOperation的block中,然后start。

- (void)testNSBlockOperation {
    // 把任務(wù)放到block中
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"NSBlockOperation包含的任務(wù),沒有加入隊(duì)列========%@", [NSThread currentThread]);
    }];
 
    [blockOperation start];
}

執(zhí)行結(jié)果如下,可以看出:主線程執(zhí)行,沒有開啟新線程。

同樣的,NSBlockOperation可以配合隊(duì)列NSOperationQueue來實(shí)現(xiàn)多線程。
NSBlockOperation包含的任務(wù),沒有加入隊(duì)列========{number = 1, name = main}
但是NSBlockOperation有一個(gè)方法addExecutionBlock:,通過這個(gè)方法可以讓NSBlockOperation實(shí)現(xiàn)多線程。

- (void)testNSBlockOperationExecution {
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"NSBlockOperation運(yùn)用addExecutionBlock主任務(wù)========%@", [NSThread currentThread]);
    }];
 
    [blockOperation addExecutionBlock:^{
        NSLog(@"NSBlockOperation運(yùn)用addExecutionBlock方法添加任務(wù)1========%@", [NSThread currentThread]);
    }];
    [blockOperation addExecutionBlock:^{
        NSLog(@"NSBlockOperation運(yùn)用addExecutionBlock方法添加任務(wù)2========%@", [NSThread currentThread]);
    }];
    [blockOperation addExecutionBlock:^{
        NSLog(@"NSBlockOperation運(yùn)用addExecutionBlock方法添加任務(wù)3========%@", [NSThread currentThread]);
    }];
    [blockOperation start];
}

執(zhí)行結(jié)果如下,可以看出,NSBlockOperation創(chuàng)建時(shí)block中的任務(wù)是在主線程執(zhí)行,而運(yùn)用addExecutionBlock加入的任務(wù)是在子線程執(zhí)行的。

NSBlockOperation運(yùn)用addExecutionBlock========{number = 1, name = main}
addExecutionBlock方法添加任務(wù)1========{number = 3, name = (null)}
addExecutionBlock方法添加任務(wù)3========{number = 5, name = (null)}
addExecutionBlock方法添加任務(wù)2========{number = 4, name = (null)}
2. 運(yùn)用繼承自NSOperation的子類

首先我們定義一個(gè)繼承自NSOperation的類,然后重寫它的main方法,之后就可以使用這個(gè)子類來進(jìn)行相關(guān)的操作了。

/*******************"WHOperation.h"*************************/
 
#import @interface WHOperation : NSOperation
 
@end
 
 
/*******************"WHOperation.m"*************************/
 
#import "WHOperation.h"
 
@implementation WHOperation
 
- (void)main {
    for (int i = 0; i < 3; i++) {
        NSLog(@"NSOperation的子類WHOperation======%@",[NSThread currentThread]);
    }
}
 
@end
 
 
/*****************回到主控制器使用WHOperation**********************/
 
- (void)testWHOperation {
    WHOperation *operation = [[WHOperation alloc] init];
    [operation start];
}

運(yùn)行結(jié)果如下,依然是在主線程執(zhí)行。

SOperation的子類WHOperation======{number = 1, name = main}
NSOperation的子類WHOperation======{number = 1, name = main}
NSOperation的子類WHOperation======{number = 1, name = main}

所以,NSOperation是需要配合隊(duì)列NSOperationQueue來實(shí)現(xiàn)多線程的。下面就來說一下隊(duì)列NSOperationQueue。

3. 隊(duì)列NSOperationQueue

NSOperationQueue只有兩種隊(duì)列:主隊(duì)列、其他隊(duì)列。其他隊(duì)列包含了串行和并發(fā)。

主隊(duì)列的創(chuàng)建如下,主隊(duì)列上的任務(wù)是在主線程執(zhí)行的。
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
其他隊(duì)列(非主隊(duì)列)的創(chuàng)建如下,加入到‘非隊(duì)列’中的任務(wù)默認(rèn)就是并發(fā),開啟多線程。
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
注意:

  1. 非主隊(duì)列(其他隊(duì)列)可以實(shí)現(xiàn)串行或并行。
  2. 隊(duì)列NSOperationQueue有一個(gè)參數(shù)叫做最大并發(fā)數(shù):maxConcurrentOperationCount。
  3. maxConcurrentOperationCount默認(rèn)為-1,直接并發(fā)執(zhí)行,所以加入到‘非隊(duì)列’中的任務(wù)默認(rèn)就是并發(fā),開啟多線程。
  4. 當(dāng)maxConcurrentOperationCount為1時(shí),則表示不開線程,也就是串行。
  5. 當(dāng)maxConcurrentOperationCount大于1時(shí),進(jìn)行并發(fā)執(zhí)行。
  6. 系統(tǒng)對(duì)最大并發(fā)數(shù)有一個(gè)限制,所以即使程序員把maxConcurrentOperationCount設(shè)置的很大,系統(tǒng)也會(huì)自動(dòng)調(diào)整。所以把最大并發(fā)數(shù)設(shè)置的很大是沒有意義的。
4. NSOperation + NSOperationQueue
  • addOperation添加任務(wù)到隊(duì)列
    先創(chuàng)建好任務(wù),然后運(yùn)用- (void)addOperation:(NSOperation *)op 方法來吧任務(wù)添加到隊(duì)列中,示例代碼如下:
- (void)testOperationQueue {
    // 創(chuàng)建隊(duì)列,默認(rèn)并發(fā)
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
 
    // 創(chuàng)建操作,NSInvocationOperation
    NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperationAddOperation) object:nil];
    // 創(chuàng)建操作,NSBlockOperation
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"addOperation把任務(wù)添加到隊(duì)列======%@", [NSThread currentThread]);
        }
    }];
 
    [queue addOperation:invocationOperation];
    [queue addOperation:blockOperation];
}
 
 
- (void)invocationOperationAddOperation {
    NSLog(@"invocationOperation===aaddOperation把任務(wù)添加到隊(duì)列====%@", [NSThread currentThread]);
}

運(yùn)行結(jié)果如下,可以看出,任務(wù)都是在子線程執(zhí)行的,開啟了新線程!

invocationOperation===addOperation把任務(wù)添加到隊(duì)列===={number = 4, name = (null)}
addOperation把任務(wù)添加到隊(duì)列======{number = 3, name = (null)}
addOperation把任務(wù)添加到隊(duì)列======{number = 3, name = (null)}
addOperation把任務(wù)添加到隊(duì)列======{number = 3, name = (null)}
5. NSOperation的其他操作
  • 取消隊(duì)列NSOperationQueue的所有操作,NSOperationQueue對(duì)象方法
    - (void)cancelAllOperations
  • 取消NSOperation的某個(gè)操作,NSOperation對(duì)象方法
    - (void)cancel
  • 使隊(duì)列暫?;蚶^續(xù)
// 暫停隊(duì)列
[queue setSuspended:YES];
  • 判斷隊(duì)列是否暫停
    - (BOOL)isSuspended
    暫停和取消不是立刻取消當(dāng)前操作,而是等當(dāng)前的操作執(zhí)行完之后不再進(jìn)行新的操作。
6. NSOperation的操作依賴

NSOperation有一個(gè)非常好用的方法,就是操作依賴。可以從字面意思理解:某一個(gè)操作(operation2)依賴于另一個(gè)操作(operation1),只有當(dāng)operation1執(zhí)行完畢,才能執(zhí)行operation2,這時(shí),就是操作依賴大顯身手的時(shí)候了。

- (void)testAddDependency {
 
    // 并發(fā)隊(duì)列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
 
    // 操作1
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"operation1======%@", [NSThread  currentThread]);
        }
    }];
 
    // 操作2
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"****operation2依賴于operation1,只有當(dāng)operation1執(zhí)行完畢,operation2才會(huì)執(zhí)行****");
        for (int i = 0; i < 3; i++) {
            NSLog(@"operation2======%@", [NSThread  currentThread]);
        }
    }];
 
    // 使操作2依賴于操作1
    [operation2 addDependency:operation1];
    // 把操作加入隊(duì)列
    [queue addOperation:operation1];
    [queue addOperation:operation2];
}

運(yùn)行結(jié)果如下,操作2總是在操作1之后執(zhí)行,成功驗(yàn)證了上面的說法。

operation1======{number = 3, name = (null)}
operation1======{number = 3, name = (null)}
operation1======{number = 3, name = (null)}
****operation2依賴于operation1,只有當(dāng)operation1執(zhí)行完畢,operation2才會(huì)執(zhí)行****
operation2======{number = 4, name = (null)}
operation2======{number = 4, name = (null)}
operation2======{number = 4, name = (null)}
至此,NSOperation的相關(guān)內(nèi)容敘述完畢,如果不足,請(qǐng)批評(píng)指正 , 謝謝 !
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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