目錄
一、NSInvocationOperation
二、NSBlockOperation
三、NSOperationQueue
NSOperation 是一個抽象類,線程安全,不需要添加額外的鎖
使用其子類:NSInvocationOperation 和 NSBlockOperation
1、NSInvocationOperation
一個對象,表示一個任務
預設在主線程中同步順序執行,想要并行異步,需要搭配`NSOperationQueue`使用
同步/異步,通過設定最大并發數`maxConcurrentOperationCount`實作:1:串行 >=2:并行 預設:-1 異步(無窮大)
2、NSBlockOperation
一個對象,可以建立多個任務
blockOperationWithBlock 添加的任務預設在主線程中
addExecutionBlock 添加任務,會開啟多個線程,并發執行
一、NSInvocationOperation
一個 NSInvocationOperation 對象表示一個任務,需要手動調用 start 開啟。
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(network:) object:@{@"name":@"moxiaohui"}];
[operation setName:@"moxiaoyan"];
[operation setCompletionBlock:^{ // 任務執行完成後在子線程中執行
NSLog(@"Completion %@", [NSThread currentThread]);
}];
[operation start];
NSLog(@"是否阻塞主線程"); // 會
- (void)network:(NSDictionary *)info {
NSLog(@"執行 operation %@ %@", [NSThread currentThread], info);
sleep(2);
NSLog(@"完成 operation");
}
// 執行結果:
// 執行 operation <NSThread: 0x600000c24040>{number = 1, name = main} {
name = moxiaohui;
}
// 完成 operation
// 是否阻塞主線程
// Completion <NSThread: 0x600003139680>{number = 4, name = (null)}
複制
從執行結果可以看得出來,預設是在主線程中執行的,而且會阻塞主線程。
若想實作異步并發,需要結合 NSOperationQueue 使用:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 設定最大并發數: 1:串行 >=2:并行 預設:-1(無窮大)
// 注意:設定的是隊列裡面最多能并發運作的操作任務個數,而不是線程個數, (另外開啟線程的數量是由系統決定的,是以這個值具體表示什麼?)
[queue setMaxConcurrentOperationCount:2];
// 将任務添加到隊列中
[queue addOperation:operation];
NSLog(@"是否阻塞主線程");
// 執行結果:
// 是否阻塞主線程
// 執行 operation <NSThread: 0x6000005e44c0>{number = 5, name = (null)} {
name = moxiaohui;
}
複制
NSOperationQueue一些其他的屬性和方法:
// 可以設定特殊的先後執行順序:addDependency
[operation2 addDependency:operation1]; // 添加依賴
[operation3 removeDependency:operation1]; // 移除依賴
[operation start]; // NSInvocationOperation alloc init 建立的需要手動開啟
[operation cancel]; // 取消單個任務,隻會對還未執行的任務有效
[operation waitUntilFinished]; // 阻塞目前線程,直到任務執行完畢後繼續 (最好不要在主線程中等待,會阻塞)
// 觀察任務狀态:
[operation isReady]; // 是否就緒
[operation isExecuting]; // 是否正在執行中
[operation isFinished]; // 是否執行完畢
[operation isCancelled]; // 是否已取消
[operation isAsynchronous]; // 是否異步執行
[operation isConcurrent]; // 已廢棄,用`isAsynchronous`
NSOperationQueuePriority priority = [operation queuePriority]; // 優先級
NSArray<NSOperation *> *dependencies = [operation dependencies]; // 依賴的任務數組
複制
二、NSBlockOperation
NSBlockOperation *block = [NSBlockOperation blockOperationWithBlock:^{ // 預設在主線程中
NSLog(@"執行2 block %@", [NSThread currentThread]);
sleep(1);
NSLog(@"完成2 block");
}];
// 通過 addExecutionBlock 添加的任務,會開辟多個子線程
[block addExecutionBlock:^{
NSLog(@"執行3 block %@", [NSThread currentThread]);
sleep(1);
NSLog(@"完成3 block");
}];
[block addExecutionBlock:^{
NSLog(@"執行4 block %@", [NSThread currentThread]);
sleep(3);
NSLog(@"完成4 block");
}];
[block addExecutionBlock:^{
NSLog(@"執行5 block %@", [NSThread currentThread]);
sleep(2);
NSLog(@"完成5 block");
}];
[block start];
NSLog(@"是否阻塞主線程"); // 會
// 執行結果:
// 執行3 block <NSThread: 0x600003a9cd80>{number = 5, name = (null)}
// 執行2 block <NSThread: 0x600003a982c0>{number = 6, name = (null)}
// 執行5 block <NSThread: 0x600003aced40>{number = 1, name = main}
// 執行4 block <NSThread: 0x600003a97740>{number = 3, name = (null)}
// 完成2 block
// 完成3 block
// 完成5 block
// 完成4 block
// 是否阻塞主線程
複制
從執行結果可以看出來,任務一多,就不确定哪個任務會主線程中執行了,是以感覺還是用queue比較保險
三、NSOperationQueue
NSOperationQueue 操作隊列,管理Operation對象,根據Operation開辟适量的線程
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 設定最大并發數: 1:同步 >=2:異步 預設:-1(無窮大)
// 注意:設定的是隊列裡面最多能并發運作的操作任務個數,而不是線程個數, (另外開啟線程的數量是由系統決定的,是以這個值具體表示什麼?)
[queue setMaxConcurrentOperationCount:2];
// 将任務添加到隊列中
[queue addOperation:operation];
NSLog(@"是否阻塞主線程");
[queue addOperation:block];
[queue addOperationWithBlock:^{
NSLog(@"執行6 %@", [NSThread currentThread]);
sleep(2);
NSLog(@"完成6");
}];
[queue addBarrierBlock:^{ // 隊列中所有任務完成後執行
NSLog(@"all complete");
}];
[queue setSuspended:YES]; // 暫停隊列
[queue setSuspended:NO]; // 繼續隊列
[queue cancelAllOperations]; // 取消所有任務
[queue waitUntilAllOperationsAreFinished]; // 阻塞目前線程,直到所有任務執行完畢後繼續(最好不要在主線程中等待,會阻塞)
複制
Demo github 位址