一:简介
1.简介
NSOperation是一个抽象的基类,表示一个独立的计算单元,可以为子类提供有用且线程安全的建立状态,优先级,依赖和取消等操作。系统已经给我们封装了NSBlockOperation和NSInvocationOperation 这两个实体类。
2.执行和监听操作
NSOperation调用start方法即可开始执行操作,NSOperation对象默认按同步方式执行,也就是在start方法的那个线程中直接执行。
如果我们想在一个NSOperation执行完毕后做一些事情,就调用NSOperation的setCompletionBlock方法来设置想做的事情
3.NSOperation的子类
使用NSOperation子类的方式有3种
- NSInvocationOperation
- NSBlockOperation
- 自定义子类继承NSOperation,实现内部相应的方法
二:具体使用
1.NSInvocationOperation
1.1 简介:
基于一个对象和selector来创建操作。如果你已经有现有的方法来执行需要的任务,就可以使用这个类
1.2 创建并执行操作
- (void)testNSInvocationOperation{
//创建任务NSInvocationOperation 使用start开启,默认是同步执行
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downImage) object:nil];
//监听任务结束
[operation setCompletionBlock:^{
NSLog(@"任务结束,当前线程==%@",[NSThread currentThread]);
}];
//开启任务,不写下面start,不会执行对应方法
[operation start];
}
- (void)downImage{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"下载图片1,当前线程==%@",[NSThread currentThread]);
}
打印结果:
2018-07-30 15:35:19.812267+0800 ThreadTest[40247:401579] 下载图片1,当前线程==<NSThread: 0x60c00006e740>{number = 1, name = main}
2018-07-30 15:35:19.812545+0800 ThreadTest[40247:401622] 任务结束,当前线程==<NSThread: 0x60800006f940>{number = 3, name = (null)}
2.NSBlockOperation
2.1 简介
能够并发的执行一个或多个block对象,所有相关的block都执行完成后,操作才算完成
2.2创建并执行操作
- (void)testNSBlockOperation{
//创建任务NSInvocationOperation 使用start开启,默认是同步执行
NSBlockOperation *blockOP = [NSBlockOperation blockOperationWithBlock:^{
//任务
[self downImage];
}];
//添加任务
[blockOP addExecutionBlock:^{
ZWWLog(@"任务2,当前线程==%@",[NSThread currentThread]);
}];
//添加任务
[blockOP addExecutionBlock:^{
ZWWLog(@"任务3,当前线程==%@",[NSThread currentThread]);
}];
//开启任务(这里还是同步执行),不写下面start,不会执行对应方法
[blockOP start];
}
打印结果:
2018-07-30 15:40:21.767030+0800 ThreadTest[40740:406975] 任务3,当前线程==<NSThread: 0x604000262b80>{number = 4, name = (null)}
2018-07-30 15:40:21.767030+0800 ThreadTest[40740:406974] 任务2,当前线程==<NSThread: 0x60c00047a580>{number = 3, name = (null)}
2018-07-30 15:40:22.767559+0800 ThreadTest[40740:406915] 下载图片1,当前线程==<NSThread: 0x60c00007ab40>{number = 1, name = main}
3.NSOperationQueue
简介:
一个NSOperationQueue对象可以通过调用start方法来执行任务,默认是同步执行的。也可以将NSOperation添加到一个NSOperationQueue(操作队列)中去执行,而且是异步执行的。
//3.NSOperationQueue
- (void)testNSOperationQueue{
//1.创建操作队列;全局并发队列,添加到队列里的任务都是异步执行的
//NSOperationQueue相当于GCD中的 dispatch_get_global_queue
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//2.创建任务
NSInvocationOperation *invoOP = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downImage) object:nil];
// [queue addOperation:invoOP];
NSBlockOperation *blockOP = [NSBlockOperation blockOperationWithBlock:^{
//任务
[self downImage];
}];
//添加任务到队列方法1
// [queue addOperation:blockOP];
//3.添加多个任务到队列方法2
[queue addOperations:@[invoOP,blockOP] waitUntilFinished:YES];
//添加任务到队列方法2
// [queue addOperationWithBlock:^{
// NSLog(@"直接添加block任务,当前线程==%@",[NSThread currentThread]);
// }];
//
//
// dispatch_async(dispatch_get_global_queue(0, 0), ^{
// ZWWLog(@"等同以上NSOperation操作");
// });
}
打印结果:
2018-07-30 15:50:11.095684+0800 ThreadTest[41716:418465] 下载图片1,当前线程==<NSThread: 0x604000073440>{number = 3, name = (null)}
2018-07-30 15:50:11.095684+0800 ThreadTest[41716:418463] 下载图片1,当前线程==<NSThread: 0x60c00007ffc0>{number = 4, name = (null)}
4.最大并发数:maxConcurrentOperationCount
- (void)testOperationCount{
//设置最大并发量,设置之后会两个两个一起来打印,不设置的话10个循环几乎同一时间并发打印
//情况类似于 百度网盘同时勾选两个文件夹下载(可以把网速集中到某两个文件夹的下载上),不设置并发数的话,会多个线程共同并发执行,多个文件没有重要性区分
self.opQueue.maxConcurrentOperationCount = 2;
for (int i = 0; i<10; i++) {
NSInvocationOperation *invoOP = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downImage) object:nil];
[self.opQueue addOperation:invoOP];
}
}
打印结果:
2018-07-30 16:00:52.356566+0800 ThreadTest[42570:428532] 下载图片1,当前线程==<NSThread: 0x60c00006c8c0>{number = 4, name = (null)}
2018-07-30 16:00:52.356573+0800 ThreadTest[42570:431306] 下载图片1,当前线程==<NSThread: 0x608000073700>{number = 6, name = (null)}
2018-07-30 16:00:53.360346+0800 ThreadTest[42570:428532] 下载图片1,当前线程==<NSThread: 0x60c00006c8c0>{number = 4, name = (null)}
2018-07-30 16:00:53.360392+0800 ThreadTest[42570:431313] 下载图片1,当前线程==<NSThread: 0x604000464100>{number = 7, name = (null)}
2018-07-30 16:00:54.362835+0800 ThreadTest[42570:431313] 下载图片1,当前线程==<NSThread: 0x604000464100>{number = 7, name = (null)}
2018-07-30 16:00:54.362835+0800 ThreadTest[42570:431306] 下载图片1,当前线程==<NSThread: 0x608000073700>{number = 6, name = (null)}
2018-07-30 16:00:55.366234+0800 ThreadTest[42570:431313] 下载图片1,当前线程==<NSThread: 0x604000464100>{number = 7, name = (null)}
2018-07-30 16:00:55.366255+0800 ThreadTest[42570:428532] 下载图片1,当前线程==<NSThread: 0x60c00006c8c0>{number = 4, name = (null)}
2018-07-30 16:00:56.369255+0800 ThreadTest[42570:431306] 下载图片1,当前线程==<NSThread: 0x608000073700>{number = 6, name = (null)}
2018-07-30 16:00:56.369255+0800 ThreadTest[42570:428532] 下载图片1,当前线程==<NSThread: 0x60c00006c8c0>{number = 4, name = (null)}
但是打印时,会两个两个一起来打印,不设置最大并发量的话10个循环几乎同一时间并发打印
5.依赖关系
- (void)testDependency{
NSInvocationOperation *invoOP1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downImage) object:nil];
NSBlockOperation *blockOP2 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:10.0];
NSLog(@"下载图片2,当前线程==%@",[NSThread currentThread]);
}];
NSBlockOperation *blockOP3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下载图片3,当前线程==%@",[NSThread currentThread]);
}];
NSBlockOperation *blockOP4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"更新UI,当前线程==%@",[NSThread currentThread]);
}];
//添加依赖关系 invoOP1依赖blockOP2,blockOP2依赖blockOP3,所以先执行blockOP3
[blockOP4 addDependency:invoOP1];
[invoOP1 addDependency:blockOP2];
[blockOP2 addDependency:blockOP3];
[self.opQueue addOperations:@[invoOP1,blockOP2,blockOP3,blockOP4] waitUntilFinished:YES];
}
打印结果:
2018-07-30 15:58:22.415302+0800 ThreadTest[42570:428530] 下载图片3,当前线程==<NSThread: 0x604000466b00>{number = 3, name = (null)}
2018-07-30 15:58:32.419422+0800 ThreadTest[42570:428532] 下载图片2,当前线程==<NSThread: 0x60c00006c8c0>{number = 4, name = (null)}
2018-07-30 15:58:33.422490+0800 ThreadTest[42570:428532] 下载图片1,当前线程==<NSThread: 0x60c00006c8c0>{number = 4, name = (null)}
2018-07-30 15:58:33.422745+0800 ThreadTest[42570:428531] 更新UI,当前线程==<NSThread: 0x600000064140>{number = 5, name = (null)}
可以看到:
invoOP1依赖blockOP2,blockOP2依赖blockOP3,所以先执行blockOP3