「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战」
关于NSOperationQueue
NSOperationQueue 一共有两种队列:
-
主队列
//获取主队列 NSOperationQueue *queue = [NSOperationQueue mainQueue]; -
自定义队列:通过设置最大并发数属性来控制任务是并发执行还是串行执行
- 并发执行
- 串行执行
//获取自定义队列 NSOperationQueue *queue = [[NSOperationQueue alloc]init];
NSInvocationOperation 和 NSOperationQueue 组合
示例:
//创建队列(创建的队列中的任务默认是异步执行的)
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//创建任务
NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run1) object:nil];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run2) object:nil];
//任务添加队列
[queue addOperation:op1];
[queue addOperation:op2];
- (void)run1{
NSLog(@"1-- %@",[NSThread currentThread]);
}
- (void)run2{
NSLog(@"2-- %@",[NSThread currentThread]);
}
log:
NSInvocationOperation 和 NSBlockOperation 组合
示例:
//创建队列(创建的队列中的任务默认是异步执行的)
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//创建任务
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1-- %@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2-- %@",[NSThread currentThread]);
}];
//添加额外任务
[op1 addExecutionBlock:^{
NSLog(@"3-- %@",[NSThread currentThread]);
}];
//添加额外任务
[op1 addExecutionBlock:^{
NSLog(@"4-- %@",[NSThread currentThread]);
}];
//任务添加队列
[queue addOperation:op1];
[queue addOperation:op2];
//可以直接创建任务到队列中去
[queue addOperationWithBlock:^{
NSLog(@"5-- %@",[NSThread currentThread]);
}];
log:(任务都是并发执行的)
NSInvocationOperation 和 自定义NSOperation 组合
示例:
//创建队列(创建的队列中的任务默认是异步执行的)
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//创建任务需要继承NSOperation,执行的操作需要放在这个自定义类的main中
Operation *op1 = [[Operation alloc]init];
//创建任务需要继承NSOperation,执行的操作需要放在这个自定义类的main中
Operation *op2 = [[Operation alloc]init];
//任务添加队列
[queue addOperation:op1];
[queue addOperation:op2];
log:
NSOperation其它用法
设置最大并发数(控制任务并发和串行)
- 最大并发数:队列在同一时间中最多有多少个任务可以执行
- 通过属性
maxConcurrentOperationCount设置最大并发数量maxConcurrentOperationCount = -1,不进行限制,并发执行maxConcurrentOperationCount = 1,串行队列,串行执行maxConcurrentOperationCount > 1,并发队列,并发执行maxConcurrentOperationCount = 0,不会执行
注:
- 同一时间最多有多少个任务可以执行
- 串行执行并不是只开一条线程,它只是线程同步,区别串行还是并行,不是看它开了多少条线程,而是看任务的执行方式,是有序的还是无序的
示例:(设置最大并发数为1,队列为串行执行任务)
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//最大并发数设置为1
queue.maxConcurrentOperationCount = 1;
[queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:2];
NSLog(@"1-- %@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:2];
NSLog(@"2-- %@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:2];
NSLog(@"3-- %@",[NSThread currentThread]);
}];
log:(线程为多条,但是属于线程同步)
示例:(设置最大并发数为2,队列为串行执行任务)
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//最大并发数设置为1
queue.maxConcurrentOperationCount = 2;
[queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:2];
NSLog(@"1-- %@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:2];
NSLog(@"2-- %@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:2];
NSLog(@"3-- %@",[NSThread currentThread]);
}];
log:(线程为多条,异步执行,不管加入队列有多少操作,实际队列并发数为2)
队列的暂停和恢复以及取消
-
暂停和恢复队列
- 暂停表示不继续执行队列中的下一个任务,暂停是可以恢复的
- 队列中的任务也是有状态的,分为:已经执行完毕、正在执行、排队等待状态
- 不能暂停当前正在处于执行状态的任务
//暂停 queue.suspended = YES; //恢复 queue.suspended = NO; -
取消队列的所有操作
- 取消队列里所有的操作
- 取消之后,当前正在执行的操作的下一个操作将不再执行
- 取消操作是不可恢复的
- 已经取消操作,再次启动需要重新加入队列
[queue cancelAllOperations]
示例:
创建队列并执行
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
self.queue = [[NSOperationQueue alloc]init];
self.queue.maxConcurrentOperationCount = 1;
[self.queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"-1--%@",[NSThread currentThread]);
}];
[self.queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"-2--%@",[NSThread currentThread]);
}];
[self.queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"-3--%@",[NSThread currentThread]);
}];
[self.queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"-4--%@",[NSThread currentThread]);
}];
}
//暂停和恢复队列
- (void)suspendedClick:(id)sender {
if(self.queue.suspended){
//恢复队列,继续执行
self.queue.suspended = NO;
}else{
//挂起(暂停队列)
self.queue.suspended = YES;
}
}
//取消队列
- (void)cancelClick:(id)sender {
[self.queue cancelAllOperations];
}
设置队列操作依赖
NSOperation之间可以设置依赖来保证执行顺序,比如A执行完之后再执行B,就可以使用设置依赖- 设置依赖
[op1 addDependency:op3]; - 取消依赖
[op1 removeDependency:op3]; - 不可以循环依赖
[op1 addDependency:op3]; [op3 addDependency:op1]; - 设置监听:监听一个操作的执行完毕
[op2 setCompletionBlock:^{ NSLog(@"2执行完成"); }];
示例:
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1---%@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2---%@",[NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"3---%@",[NSThread currentThread]);
}];
//设置依赖(op1和op3执行完之后才执行2)
[op1 addDependency:op3];
[op2 addDependency:op1];
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
//监听一个操作的执行完成
[op2 setCompletionBlock:^{
NSLog(@"2执行完成");
}];
log:(依赖可知优先级:op3 > op1 > op2,监听的操作不一定和被监听的操作同一个线程,都是异步的,只是op3执行结束,肯定会执行监听的操作)
监控NSOperation对象的属性
isExecuting表示任务正在执行中isFinished表示任务已经执行完成,被取消也算执行完成isCancelled表示任务已经取消执行isAsynchronous表示任务是并发还是同步执行isReady表示任务是并发还是同步执行
队列里的优先级
- iOS8以前,
NSOperation通过设置queuePriority属性来设置优先级 - iOS 8.0后,
NSOperation通过设置qualityOfService来设置优先级 - 优先级高的先执行,低的后执行
//iOS8以前的优先级(queuePriority)
typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
};
//iOS8以后的优先级(qualityOfService)
typedef NS_ENUM(NSInteger, NSQualityOfService) {
NSQualityOfServiceUserInteractive = 0x21,//最高优先级,用于用户交互事件
NSQualityOfServiceUserInitiated = 0x19,//次高优先级,用于用户需要马上执行的事件
NSQualityOfServiceUtility = 0x11,//默认优先级,主线程和没有设置优先级的线程都默认为这个优先级
NSQualityOfServiceBackground = 0x09,//普通优先级,用于普通任务
NSQualityOfServiceDefault = -1//最低优先级,用于不重要的任务
}
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"down1---%@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"down2---%@",[NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"down3---%@",[NSThread currentThread]);
}];
//设置优先级
op3.qualityOfService = NSQualityOfServiceUserInteractive;
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
log: