iOS 多線程之NSOperation篇舉例詳解

  這篇博客是接着總篇iOS GCD NSOperation NSThread等多線程各類舉例詳解寫的一個支篇。總篇也包含了此文的連接。本文講解的知識點有NSBlockOperationClick,隊列,隊列中如何加Operation,Operation中如何加任務,Operation之間的串行、並行,監控任務完成時機及其餘一些關於NSOperation的方法,每一個知識點都有例子和詳細分析。附上demo下載地址html

1、NSOperation介紹

  NSOperation 是蘋果公司對 GCD 的封裝,徹底面向對象。NSOperation實例封裝了須要執行的操做和執行操做所需的數據,而且可以以併發或非併發的方式執行這個操做。NSOperation自己是抽象基類,所以可使用它的子類NSInvocationOperation 和 NSBlockOperation,或者自定義子類也行。NSOperation 和 NSOperationQueue 能夠當作是GCD的任務和隊列。git

2、NSInvocationOperation(不是類型安全的,蘋果在swift裏不用它了)

  可是我仍是來說講,證實它曾經存在過。NSInvocationOperation建立一個 Operation 後,須要調用 start 方法來啓動任務,它會 默認在當前隊列同步執行。舉個例子
github

- (IBAction)NSInvocationOperationClick:(id)sender { //1.建立NSInvocationOperation對象
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(myTask) object:nil]; operation.completionBlock = ^() { NSLog(@"執行完畢"); }; //2.在當前線程執行
 [operation start]; NSLog(@"阻塞我沒有?當前線程%@",[NSThread currentThread]); } //模擬很耗時的任務
-(void)myTask { for (NSInteger i = 0; i < 500000000; i++) { if (i == 0) { NSLog(@"任務 -> 開始"); } if (i == 499999999) { NSLog(@"任務 -> 完成"); } } }

 

打印結果:swift

分析結論:從打印結果看,會阻塞當前線程,由於他是同步執行的。安全

3、NSBlockOperationClick

  在block中加任務,使用更方便,代碼更緊湊,舉個例子。多線程

- (IBAction)NSBlockOperationClick:(id)sender { //1.建立NSBlockOperation對象
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ [self myTask]; }]; //2.也能夠添加多個Block,經過這個方法能夠給 Operation 添加多個執行 Block。這樣 Operation 中的任務 會併發執行,它會 在主線程和其它的多個線程 執行這些任務
    for (NSInteger n = 0; n < 3; n++) { [operation addExecutionBlock:^{ for (NSInteger i = 0; i < 500000000; i++) { if (i == 0) { NSLog(@"任務%ld -> 開始",n); } if (i == 499999999) { NSLog(@"任務%ld -> 完成",n); } } }]; } operation.completionBlock = ^() { NSLog(@"執行完畢"); }; //3.開始任務
 [operation start]; NSLog(@"阻塞我沒有?當前線程%@",[NSThread currentThread]); }

打印結果:併發

分析結論:給 Operation 添加多個執行 Block任務,Operation 中的任務會併發執行,它會在主線程和其它的多個線程執行這些任務,會阻塞當前主線程。spa

4、主隊列

  舉個例子線程

//主隊列裏的任務並行執行,且不阻塞當前線程。(隊列中加多個operation時另說,看第五個例子就知道了)
- (IBAction)mainQueue:(id)sender { NSOperationQueue *queue = [NSOperationQueue mainQueue]; //建立NSBlockOperation對象
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ [self myTask]; }]; for (NSInteger n = 0; n < 3; n++) { [operation addExecutionBlock:^{ for (NSInteger i = 0; i < 500000000; i++) { if (i == 0) { NSLog(@"主隊列中任務%ld -> 開始%@",n,[NSThread currentThread]); } if (i == 499999999) { NSLog(@"主隊列中任務%ld -> 完成",n); } } }]; } operation.completionBlock = ^() { NSLog(@"執行完畢"); }; //加入到隊列中任務自動執行
 [queue addOperation:operation]; NSLog(@"阻塞我沒有?當前線程%@",[NSThread currentThread]); }

打印結果:code

分析結論:主隊列裏的任務都是另開線程並行執行的,不會阻塞當前線程。(隊列中加多個operation時另說,請看下面例子)

5、其餘隊列

  基本用法跟主隊列差很少,我將在這個例子裏列舉更多用法。在一個隊列里加2個operation,第一個operation里加2個任務。舉個例子

- (IBAction)otherQueue:(id)sender { //1.建立一個其餘隊列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //最大併發數,用來設置最多可讓多少個operation同時執行。當你把它設置爲 1 的時候,就是串行了(指多個operation的串行,同一個operation中的任務是並行的)
    queue.maxConcurrentOperationCount = 1; //2.建立NSBlockOperation對象
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{ for (NSInteger i = 0; i < 500000000; i++) { if (i == 0) { NSLog(@"operation1中任務1 -> 開始"); } if (i == 499999999) { NSLog(@"operation1中任務1 -> 完成"); } } }]; //3.給operation1再加一個任務
    [operation1 addExecutionBlock:^{ for (NSInteger i = 0; i < 500000000; i++) { if (i == 0) { NSLog(@"operation1中任務2 -> 開始"); } if (i == 499999999) { NSLog(@"operation1中任務2 -> 完成"); } } }]; operation1.completionBlock = ^() { NSLog(@"執行完畢"); }; //4.再加一個operation2
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{ for (NSInteger i = 0; i < 500000000; i++) { if (i == 0) { NSLog(@"operation2中任務 -> 開始"); } if (i == 499999999) { NSLog(@"operation2中任務 -> 完成"); } } }]; //5.加入到隊列中任務自動執行,waitUntilFinished爲yes會阻塞當前線程,爲no不阻塞
 [queue addOperations:@[operation1,operation2] waitUntilFinished:NO]; NSLog(@"阻塞我沒有?當前線程%@",[NSThread currentThread]); }

打印結果:

分析結論:2個operation是串行的,但同一個operation中的多個任務是並行的

6、任務依賴

  任務一完成的狀況下才能執行任務二,任務二完成的狀況下才能執行任務三,舉個例子。

//任務依賴
- (IBAction)addDependency:(id)sender { //1.任務一
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"任務1開始"); [NSThread sleepForTimeInterval:1.0]; NSLog(@"任務1完成"); }]; //2.任務二
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"任務2開始"); [NSThread sleepForTimeInterval:1.0]; NSLog(@"任務2完成"); }]; //3.任務三
    NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"任務3開始"); [NSThread sleepForTimeInterval:1.0]; NSLog(@"任務3完成"); }]; //4.設置依賴
    [operation2 addDependency:operation1];      //任務二依賴任務一
    [operation3 addDependency:operation2];      //任務三依賴任務二 //5.建立隊列並加入任務
    NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperations:@[operation3, operation2, operation1] waitUntilFinished:NO]; }

打印結果:

分析結論:該任務依賴的任務完成了,才能執行該任務。

7、其餘相關方法

// 暫停queue
[queue setSuspended:YES]; // 繼續queue
[queue setSuspended:NO]; //會阻塞當前線程,等到某個operation執行完畢 [operation waitUntilFinished]; // 阻塞當前線程,等待queue的全部操做執行完畢
[queue waitUntilAllOperationsAreFinished]; // 取消單個操做
[operation cancel]; // 取消queue中全部的操做
[queue cancelAllOperations];
相關文章
相關標籤/搜索