NSOperation須要配合NSOperationQueue來實現多線程。由於默認狀況下,NSOperation單獨使用時系統同步執行操做,並無開闢新線程的能力,只有配合NSOperationQueue才能實現異步執行。多線程
NSOperation是一個抽象類,並不具有封裝操做的能力,必須使用它的子類;併發
由於NSOperation是基於GCD的,那麼使用起來也和GCD差很少,其中,NSOperation至關於GCD中的任務,而NSOperationQueue則至關於GCD中的隊列。NSOperation實現多線程的使用步驟分爲三步:異步
a. 建立任務:先將須要執行的操做封裝到一個NSOperation對象中。學習
b. 建立隊列:建立NSOperationQueue對象。spa
c. 將任務加入到隊列中:而後將NSOperation對象添加到NSOperationQueue中。線程
以後呢,系統就會自動將NSOperationQueue中的NSOperation取出來,在新線程中執行操做。code
NSOperation是個抽象類,並不能封裝任務。咱們只有使用它的子類來封裝任務。咱們有三種方式來封裝任務。對象
1 - (void)testB { 2 // 建立NSInvocationOperation對象 3 NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil]; 4 5 // 調用start方法開始執行操做 6 [op start]; 7 } 8 9 - (void)run 10 { 11 NSLog(@"當前的線程爲--%@", [NSThread currentThread]); 12 }
結果:blog
2018-01-30 18:46:59.139360+0800 RAC[21774:638747] 當前的線程爲--<NSThread: 0x60c000070c00>{number = 1, name = main}
BlockOperation:繼承
只要BlockOperation封裝的操做數 > 1,就會異步執行操做,可是不會無限制的建立線程
let blockOpe = BlockOperation() blockOpe.queuePriority = .veryHigh blockOpe.addExecutionBlock { print("BlockOperation執行了",Thread.current) } blockOpe.addExecutionBlock { print("BlockOperation2執行了",Thread.current) } blockOpe.start() //開始執行 //blockOpe.cancel() //取消
結果:
1 NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ 2 3 NSLog(@"-當前的線程爲-%@",[NSThread currentThread]); 4 }]; 5 6 [op start];
結果:
在沒有使用NSOperationQueue、單獨使用NSBlockOperation的狀況下,NSBlockOperation也是在主線程執行操做,並無開啓新線程。
1 NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ 2 // 在主線程 3 NSLog(@"線程1------%@", [NSThread currentThread]); 4 }]; 5 6 // 添加額外的任務(在子線程執行) 7 [op addExecutionBlock:^{ 8 NSLog(@"線程2------%@", [NSThread currentThread]); 9 }]; 10 [op addExecutionBlock:^{ 11 NSLog(@"線程3------%@", [NSThread currentThread]); 12 }]; 13 [op addExecutionBlock:^{ 14 NSLog(@"線程4------%@", [NSThread currentThread]); 15 }]; 16 17 [op start];
結果:
blockOperationWithBlock:方法中的操做是在主線程中執行的,而addExecutionBlock:方法中的操做是在其餘線程中執行的
和GCD中的併發隊列、串行隊列略有不一樣的是:NSOperationQueue一共有兩種隊列:主隊列、其餘隊列。其中其餘隊列同時包含了串行、併發功能。
獲取主隊列以及添加操做到隊列,主隊列是串行隊列,不管是否設置最大並行數量都是在當前線程執行,不會建立新的線程
凡是添加到主隊列中的任務(NSOperation),都會放到主線程中執行。
1 let queue = OperationQueue.main 2 queue.addOperation { 3 for _ in 0...50000{ 4 print("OperationQueue1執行了",Thread.current) 5 } 6 }
結果:
添加到這種隊列中的任務(NSOperation),就會自動放到子線程中執行。同時包含了:串行、併發功能
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
a.
同時具有串行和併發的功能,默認狀況下是併發的,能夠手動設置爲串行隊列,經過設置最大併發數屬性來更改
1 c func racsTest() { 2 let queue = OperationQueue() 3 queue.maxConcurrentOperationCount = 10 4 queue.addOperation { 5 for _ in 0...50000{ 6 print("OperationQueue1執行了",Thread.current) 7 } 8 } 9 //addOperation已經在內部執行了start方法了
結果:
a. 取消隊列中的全部任務,除了正在執行的任務,一旦被取消,就不能回覆以前的操做。
b. 將最大操做數的值設置爲1,能夠實現任務的串行效果,可是要注意的是,並非只開一條子線程(一般會開兩條子線程,循環回收複用)
c. 最大併發數6之內,不要開太多,由於雖然任務是在子線程進行處理的,可是cpu處理這些過多的子線程可能會影響UI,讓UI卡頓。
1 queue.maxConcurrentOperationCount=2;
1 queue.cancelAllOperations()
當前正在處於執行狀態的任務是不可以暫停的,只能暫停等待的任務
1 queue.isSuspended = true //暫停隊列 2 queue.isSuspended = false //恢復隊列
等待Options完成
若是須要在當前線程中處理operation完成後的結果,能夠使用NSOperation的waitUntilFinished方法阻塞當前線程,等待operation完成
1 [operation waitUntilFinished];
使用NSOperationQueue的waitUntilAllOperationsAreFinished方法
1 // 阻塞當前線程,等待queue的全部操做執行完畢 2 [queue waitUntilAllOperationsAreFinished];
addDependency
方法添加一個或者多個依賴的對象,只有全部依賴的對象都已經完成操做,當前NSOperation對象纔會開始執行操做。另外,經過
removeDependency
方法來刪除依賴對象。
1 let queue = OperationQueue() 2 //設置依賴關係 3 let blockOpe1 = BlockOperation() 4 blockOpe1.addExecutionBlock { 5 print("blockOpe1執行了") 6 } 7 let blockOpe2 = BlockOperation() 8 blockOpe2.addExecutionBlock { 9 print("blockOpe2執行了") 10 } 11 blockOpe1.addDependency(blockOpe2) 12 queue.addOperation(blockOpe1) 13 queue.addOperation(blockOpe2) 14 // 能夠看出,先執行blockOpe2,再執行blockOpe1 15
結果:
默認全部operation都擁有「普通」優先級,不過能夠經過setQueuePriority:方法來提高或下降operation對象的優先級。
1 let queue = OperationQueue() 2 queue.maxConcurrentOperationCount = 3 3 4 let blockOpe = BlockOperation() 5 blockOpe.addExecutionBlock { 6 print("blockOpe------------>執行了") 7 } 8 blockOpe.queuePriority = .veryHigh 9 10 let blockOpe1 = BlockOperation() 11 blockOpe1.addExecutionBlock { 12 print("blockOpe1------------>執行了") 13 } 14 blockOpe1.queuePriority = .low 15 16 queue.addOperation(blockOpe1) 17 queue.addOperation(blockOpe)
結果:
1 // 定義一個繼承自NSOperation的子類,重寫main方法 2 // YSCOperation.h 3 #import <Foundation/Foundation.h> 4 5 @interface YSCOperation : NSOperation 6 7 @end 8 9 10 // YSCOperation.m 11 12 #import "YSCOperation.h" 13 14 @implementation YSCOperation 15 /** 16 * 須要執行的任務 17 */ 18 19 - (void)main 20 { 21 for (int i = 0; i < 2; ++i) { 22 NSLog(@"--i---%@",[NSThread currentThread]); 23 } 24 } 25 26 @end 27 28 29 30 // 導入頭文件YSCOperation.h 31 // 建立YSCOperation 32 YSCOperation *op1 = [[YSCOperation alloc] init]; 33 34 [op1 start];
結果:
--0---<NSThread: 0x6080000779c0>{number = 1, name = main} --1---<NSThread: 0x6080000779c0>{number = 1, name = main}
在沒有使用NSOperationQueue、單獨使用自定義子類的狀況下,是在主線程執行操做,並無開啓新線程。