这篇博客是接着总篇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];