Operation(Swift)

介紹:

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是個抽象類,並不能封裝任務。咱們只有使用它的子類來封裝任務。咱們有三種方式來封裝任務。對象

使用子類 NSInvocationOperation
使用子類 NSBlockOperation
定義繼承自 NSOperation的子類,經過實現內部相應的方法來封裝任務。
在不使用NSOperationQueue,單獨使用NSOperation的狀況下系統同步執行操做,下面咱們學習如下任務的三種建立方式。

 


 

NSInvocationOperation 

OC版

 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:繼承

Swift 版

只要BlockOperation封裝的操做數 > 1,就會異步執行操做,可是不會無限制的建立線程

let blockOpe = BlockOperation()
        blockOpe.queuePriority = .veryHigh
        blockOpe.addExecutionBlock {
            print("BlockOperation執行了",Thread.current)
        }
        blockOpe.addExecutionBlock {
            print("BlockOperation2執行了",Thread.current)
        }
        blockOpe.start()  //開始執行
        //blockOpe.cancel() //取消

結果:

 

OC 版

1     NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
2         
3         NSLog(@"-當前的線程爲-%@",[NSThread currentThread]);
4     }];
5     
6     [op start];

結果:

在沒有使用NSOperationQueue、單獨使用NSBlockOperation的狀況下,NSBlockOperation也是在主線程執行操做,並無開啓新線程。

 

addExecutionBlock

 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:方法中的操做是在其餘線程中執行的

 


 

 

NSOperationQueue

和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];

 


 

 

 

添加NSOperation的依賴對象

當某個NSOperation對象依賴於其它NSOperation對象的完成時,就能夠經過 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         

結果:

 

 


 

 

 

修改Operations的執行順序

默認全部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)

結果:

 

 


 

 

定義NSOperation的子類

 

 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、單獨使用自定義子類的狀況下,是在主線程執行操做,並無開啓新線程。

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息