這篇文章里我將不過多的談及理論知識,這些東西會的自然會,不會的,看多了也是雲里霧裡。下麵我講更多的用代碼+註釋的方式來講如何使用NSOperation和NSOperationQueue。 1、NSOperation。是抽象類,不能夠直接使用,而是使用子類NSInvocationOperation和N ...
這篇文章里我將不過多的談及理論知識,這些東西會的自然會,不會的,看多了也是雲里霧裡。下麵我講更多的用代碼+註釋的方式來講如何使用NSOperation和NSOperationQueue。
1、NSOperation。是抽象類,不能夠直接使用,而是使用子類NSInvocationOperation和NSBlockOperation來實際執行任務。NSOperation本身和多線程是沒有任何關係的,她只是封裝了一個代碼段和數據去實現一個功能。
1.1、NSInvocationOperation,基於一個對象和selector來創建操作。看下麵的代碼:
1 - (void)invocationOperation { 2 3 NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(startOpration) object:nil]; 4 [operation setCompletionBlock:^{ 5 NSLog(@"執行完成,是否主線程:%@", [NSThread isMainThread] == 1 ? @"YES" : @"NO"); 6 }]; 7 [operation start]; //啟動任務 8 [operation cancel]; //取消任務 9 [operation isExecuting]; //任務是否在執行 10 [operation isFinished]; //任務是否已經結束 11 } 12 13 - (void)startOpration { 14 NSLog(@"開始執行,是否主線程:%@", [NSThread isMainThread] == 1 ? @"YES" : @"NO"); 15 }
首先是創建了一個operation,並給operation添加了一個需要執行的方法:startOpration。其中Line4中的方法將會在operation執行完成後執行,當然不是必須的,如果需要在operation執行完進行一些操作,可以寫上這個方法。
下麵是執行的結果:
2016-05-06 20:28:19.577 NSOperation[1725:364426] 開始執行,是否主線程:YES 2016-05-06 20:28:19.577 NSOperation[1725:364462] 執行完成,是否主線程:NO
根據上面執行的結果,我們可以發現, startOpration 這個方法是在主線程執行的。至於Line4~Line6是在子線程執行的,則不在今天的討論內容中,略過。
1.2、NSBlockOperation。相對於NSInvocationOperation,NSBlockOperation則是將selector中需要調用的方法使用Block進行了封裝,使用起來更加的方便。關於Block的使用,不明白的同學可以參考我的上一篇博客。
NSBlockOperation對象能夠併發的執行一個或多個Block對象,所有相關的Block都執行完成之後,操作才算完成。下麵看代碼:
1 - (void)blockOperation { 2 //創建一個操作 3 NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ 4 NSLog(@"%d,%@,是否主線程:%@", __LINE__, [NSThread currentThread], [NSThread isMainThread] == 1 ? @"YES" : @"NO"); 5 }]; 6 //通過addExecutionBlock方法添加Block操作 7 [blockOperation addExecutionBlock:^{ 8 NSLog(@"%d,%@,是否主線程:%@", __LINE__, [NSThread currentThread], [NSThread isMainThread] == 1 ? @"YES" : @"NO"); 9 }]; 10 [blockOperation addExecutionBlock:^{ 11 NSLog(@"%d,%@,是否主線程:%@", __LINE__, [NSThread currentThread], [NSThread isMainThread] == 1 ? @"YES" : @"NO"); 12 }]; 13 [blockOperation addExecutionBlock:^{ 14 NSLog(@"%d,%@,是否主線程:%@", __LINE__, [NSThread currentThread], [NSThread isMainThread] == 1 ? @"YES" : @"NO"); 15 }]; 16 [blockOperation addExecutionBlock:^{ 17 NSLog(@"%d,%@,是否主線程:%@", __LINE__, [NSThread currentThread], [NSThread isMainThread] == 1 ? @"YES" : @"NO"); 18 }]; 19 //執行操作 20 [blockOperation start]; 21 //上面的幾個Block是併發執行的,將會在不同的線程中執行, 22 }
下麵是執行的結果:
2016-05-06 20:58:28.585 NSOperation[1754:389977] 48,<NSThread: 0x7f97cad07c30>{number = 1, name = main},是否主線程:YES 2016-05-06 20:58:28.585 NSOperation[1754:390024] 44,<NSThread: 0x7f97cae223c0>{number = 2, name = (null)},是否主線程:NO 2016-05-06 20:58:28.585 NSOperation[1754:390042] 54,<NSThread: 0x7f97cac0eb60>{number = 4, name = (null)},是否主線程:NO 2016-05-06 20:58:28.586 NSOperation[1754:389977] 57,<NSThread: 0x7f97cad07c30>{number = 1, name = main},是否主線程:YES 2016-05-06 20:58:28.585 NSOperation[1754:390030] 51,<NSThread: 0x7f97cad06530>{number = 3, name = (null)},是否主線程:NO
可以從上面的執行結果中,很容易的發現,程式是並行的執行。而創建的操作,也就是:Line4是在主線程中執行,而其他通過通過 addExecutionBlock 方法添加的Block操作則是在不同的線程中執行。
通過上面的說明,我要總結的是:NSOperation以及子類,只是一個操作,本身無主線程和子線程的區分,可以在任意線程中使用。也就是,在主線程中創建的操作將在主線程中執行,在子線程中創建的操作將在子線程中執行。而實現多線程可以配合NSOperationQueue來實現。下麵來介紹NSOperationQueue。
2.NSOperationQueue,是操作隊列,它用來管理一組NSOperation對象的執行,會根據需要自動為NSOperation對象開闢適合數量的線程,以完成任務的並行執行。下麵上代碼:
1 - (void)operationQueue { 2 //創建一個任務隊列,alloc(new)出來的任務隊列將會在子線程中執行,並且是併發執行 3 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 4 //創建操作NSInvocationOperation 5 for (int i = 0; i < 5; i++) { 6 NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(startOpration) object:nil]; 7 [queue addOperation:operation]; 8 } 9 //創建NSBlockOperation操作 10 for (int i = 0; i < 5; i++) { 11 NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ 12 NSLog(@"%d,%@,%d", __LINE__, [NSThread currentThread], [NSThread isMainThread]); 13 }]; 14 //將操作添加到隊列中 15 [queue addOperation:blockOperation]; 16 } 17 //設置最大併發數,當把最大併發數設置1時,此時隊列相當於串列執行。 18 queue.maxConcurrentOperationCount = 3; 19 //添加依賴關係 20 NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ 21 NSLog(@"這是任務1,依賴於任務2"); 22 }]; 23 NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ 24 NSLog(@"這是任務2"); 25 }]; 26 //添加依賴關係 27 //添加依賴關係時,註意不能添加互相依賴,如A依賴B,B依賴A 28 [op1 addDependency:op2]; 29 //添加依賴關係必須在任務添加到隊列之前設置 30 [queue addOperation:op1]; 31 [queue addOperation:op2]; 32 //回到主線程的操作 33 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 34 NSLog(@"%d,%@,%d", __LINE__, [NSThread currentThread], [NSThread isMainThread]); 35 }]; 36 }
下麵是執行的結果:
1 2016-05-06 21:15:11.625 NSOperation[1770:402666] 開始執行,是否主線程:NO 2 2016-05-06 21:15:11.625 NSOperation[1770:402633] 開始執行,是否主線程:NO 3 2016-05-06 21:15:11.625 NSOperation[1770:402642] 開始執行,是否主線程:NO 4 2016-05-06 21:15:11.625 NSOperation[1770:402654] 開始執行,是否主線程:NO 5 2016-05-06 21:15:11.625 NSOperation[1770:402664] 開始執行,是否主線程:NO 6 2016-05-06 21:15:11.626 NSOperation[1770:402665] 75,<NSThread: 0x7f852bc099f0>{number = 2, name = (null)},0 7 2016-05-06 21:15:11.627 NSOperation[1770:402667] 75,<NSThread: 0x7f852bf0db10>{number = 3, name = (null)},0 8 2016-05-06 21:15:11.628 NSOperation[1770:402633] 75,<NSThread: 0x7f852bc46ee0>{number = 4, name = (null)},0 9 2016-05-06 21:15:11.628 NSOperation[1770:402666] 75,<NSThread: 0x7f852bc4fe00>{number = 6, name = (null)},0 10 2016-05-06 21:15:11.628 NSOperation[1770:402642] 75,<NSThread: 0x7f852be0a130>{number = 5, name = (null)},0 11 2016-05-06 21:15:11.629 NSOperation[1770:402633] 這是任務2 12 2016-05-06 21:15:11.629 NSOperation[1770:402633] 這是任務1,依賴於任務2 13 2016-05-06 21:15:11.631 NSOperation[1770:402393] 97,<NSThread: 0x7f852bd05190>{number = 1, name = main},1
從上面的執行結果中,我們可以得到幾個結論:1.首先隊列中的任務都是在子線程中執行的;2.隊列中的任務是併發執行的。而常用到的添加依賴關係,以及操作完成之後回到主線程的方法在上面的代碼中都有體現。
需要說明的是,一旦將operation添加到隊列中後,隊列就擁有了這個操作,操作將不能從隊列中刪除,只能取消一個操作,或者取消所有的操作。取消一個操作的方法:
[operation cancel];
取消所有操作的方法:
[queue cancelAllOperations];
如果想要暫停操作的執行可以使用方法: [queue setSuspended:YES]; 來實現。但是暫停不會導致正在執行的操作被暫停,只會阻止隊列調度新的操作執行。可以通過方法: [queue setSuspended:NO]; 來繼續隊列的執行。
3、最後做一個簡單的總結。NSInvocationOperation 和 NSBlockOperation的功能是開啟一個線程任務,這個線程任務處於子線程和主線程取決於線程任務是在哪個線程中開闢的。這些任務可以使用線程任務隊列NSOperationQueue來管理,當new一個隊列時,隊列所管理的任務都在子線程中執行.當使用[NSOperationQueue mainQueue]時,隊列管理的任務在主線程中執行。
以上就是這篇文章的多有內容,如果有不對或者不足的地方,請大家在評論中指出,大家一起討論。