這篇博客是接着總篇iOS GCD NSOperation NSThread等多線程各類舉例詳解寫的一個支篇。總篇也包含了此文的連接。本文講解的知識點有NSBlockOperationClick,隊列,隊列中如何加Operation,Operation中如何加任務,Operation之間的串行、並行,監控任務完成時機及其餘一些關於NSOperation的方法,每一個知識點都有例子和詳細分析。附上demo下載地址html
NSOperation 是蘋果公司對 GCD 的封裝,徹底面向對象。NSOperation實例封裝了須要執行的操做和執行操做所需的數據,而且可以以併發或非併發的方式執行這個操做。NSOperation自己是抽象基類,所以可使用它的子類NSInvocationOperation 和 NSBlockOperation,或者自定義子類也行。NSOperation 和 NSOperationQueue 能夠當作是GCD的任務和隊列。git
可是我仍是來說講,證實它曾經存在過。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
分析結論:從打印結果看,會阻塞當前線程,由於他是同步執行的。安全
在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
舉個例子線程
//主隊列裏的任務並行執行,且不阻塞當前線程。(隊列中加多個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時另說,請看下面例子)
基本用法跟主隊列差很少,我將在這個例子裏列舉更多用法。在一個隊列里加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中的多個任務是並行的
任務一完成的狀況下才能執行任務二,任務二完成的狀況下才能執行任務三,舉個例子。
//任務依賴 - (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]; }
打印結果:
分析結論:該任務依賴的任務完成了,才能執行該任務。
// 暫停queue [queue setSuspended:YES]; // 繼續queue [queue setSuspended:NO]; //會阻塞當前線程,等到某個operation執行完畢 [operation waitUntilFinished]; // 阻塞當前線程,等待queue的全部操做執行完畢 [queue waitUntilAllOperationsAreFinished]; // 取消單個操做 [operation cancel]; // 取消queue中全部的操做 [queue cancelAllOperations];