NSOperation
NSOperation 是苹果公司对 GCD 的封装,面向对象。 NSOperation 和 NSOperationQueue 分别对应 GCD 的 任务 和 队列 。使用如下:
1.将要执行的任务封装到一个 NSOperation 对象中
2.将此任务添加到一个 NSOperationQueue 对象中
添加任务
NSOperation 是一个抽象类,所以不能封装任务。但它有 2 个子类用于封装任务。分别是:NSInvocationOperation 和 NSBlockOperation 。创建一个 Operation 后,需要调用 start 方法来启动任务,它会 默认在当前队列同步执行。当然也可以在中途取消一个任务,只需要调用其 cancel 方法即可。
//1.创建NSBlockOperation对象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"task %@", [NSThread currentThread]);
}];
//2.开始任务
[operation start];
NSBlockOperation 还有一个方法:addExecutionBlock: ,通过这个方法可以给 Operation 添加多个执行 Block,并且addExecutionBlock添加的Block 会并发异步执行。如下:
NSLog(@"beagin %@",[NSThread currentThread]);
NSBlockOperation *blockOp = [NSBlockOperation blockOperationWithBlock:^{//当前线程
sleep(2);
NSLog(@"first %@",[NSThread currentThread]);
}];
for (NSInteger i=0; i<3; i++) {
[blockOp addExecutionBlock:^{//其他线程
sleep(2);
NSLog(@"section %@",[NSThread currentThread]);
}];
}
[blockOp start];
/*输出结果:
2017-10-12 17:15:30.638732+0800 GCDLearnAdvanced[5362:776321] beagin <NSThread: 0x608000076000>{number = 1, name = main}
2017-10-12 17:15:32.640445+0800 GCDLearnAdvanced[5362:776360] section <NSThread: 0x60c000466e40>{number = 5, name = (null)}
2017-10-12 17:15:32.640444+0800 GCDLearnAdvanced[5362:776363] section <NSThread: 0x60c000467a00>{number = 3, name = (null)}
2017-10-12 17:15:32.640445+0800 GCDLearnAdvanced[5362:776361] section <NSThread: 0x600000270a00>{number = 4, name = (null)}
2017-10-12 17:15:32.640469+0800 GCDLearnAdvanced[5362:776321] first <NSThread: 0x608000076000>{number = 1, name = main}
*/
创建队列NSOperation
-
主队列
NSOperationQueue *mQueue = [NSOperationQueue mainQueue];
其他队列
因为主队列比较特殊,所以会单独有一个类方法来获得主队列。那么通过初始化产生的队列就是其他队列了
- 串行队列
NSOperationQueue 有一个参数 maxConcurrentOperationCount 最大并发数,可以用来设置最多可以让多少个任务同时执行。当把它设置为 1 的时候,就是为串行队列
任务依赖案例:
//有 3 个任务:A: 从服务器上下载一张图片,B:给这张图片加个水印,C:把图片返回给服务器
//1.任务一:下载图片
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下载图片 - %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0];
}];
//2.任务二:打水印
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"打水印 - %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0];
}];
//3.任务三:上传图片
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"上传图片 - %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0];
}];
//4.设置依赖
[operation2 addDependency:operation1]; //任务二依赖任务一
[operation3 addDependency:operation2]; //任务三依赖任务二
//5.创建队列并加入任务
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperations:@[operation3, operation2, operation1] waitUntilFinished:YES];
NSLog(@"其他task");
/*输出结果:
2017-10-12 17:33:27.035147+0800 GCDLearnAdvanced[5494:803023] 下载图片 - <NSThread: 0x600000274dc0>{number = 3, name = (null)}
2017-10-12 17:33:28.039947+0800 GCDLearnAdvanced[5494:803025] 打水印 - <NSThread: 0x60c000266e80>{number = 4, name = (null)}
2017-10-12 17:33:29.043323+0800 GCDLearnAdvanced[5494:803025] 上传图片 - <NSThread: 0x60c000266e80>{number = 4, name = (null)}
2017-10-12 17:33:30.048417+0800 GCDLearnAdvanced[5494:802986] 其他task
*/
- 不能相互依赖,比如A依赖B,B依赖A,这样会死锁
- 可以使用 removeDependency 来解除依赖关系
- addOperations:waitUntilFinished:当传入YES时会阻塞,等待任务完毕后才会继续往下执行
指定并发数量的多任务执行案例:
NSLog(@"beagin %@",[NSThread currentThread]);
NSOperationQueue *operationQ = [[NSOperationQueue alloc]init];
operationQ.maxConcurrentOperationCount = 2;
for (NSInteger i=0; i<5; i++) {
NSBlockOperation *blockOp = [[NSBlockOperation alloc]init];
[blockOp addExecutionBlock:^{
sleep(2);
NSLog(@"first%@ %@",@(i),[NSThread currentThread]);
}];
[operationQ addOperation:blockOp];
}
/*输出结果:
2017-10-12 16:55:18.363146+0800 GCDLearnAdvanced[5194:730174] beagin <NSThread: 0x60c00006ed40>{number = 1, name = main}
2017-10-12 16:55:20.364293+0800 GCDLearnAdvanced[5194:730224] first0 <NSThread: 0x60400007f700>{number = 3, name = (null)}
2017-10-12 16:55:20.364293+0800 GCDLearnAdvanced[5194:730228] first1 <NSThread: 0x6080002722c0>{number = 4, name = (null)}
2017-10-12 16:55:22.368552+0800 GCDLearnAdvanced[5194:730225] first2 <NSThread: 0x600000269a00>{number = 5, name = (null)}
2017-10-12 16:55:22.368552+0800 GCDLearnAdvanced[5194:730221] first3 <NSThread: 0x60400007d880>{number = 6, name = (null)}
2017-10-12 16:55:24.372538+0800 GCDLearnAdvanced[5194:730228] first4 <NSThread: 0x6080002722c0>{number = 4, name = (null)}
*/
通过打印的时间我们可以看到最多只有两条线程同时异步执行。