求职广告 (2019 - 12):因上一家公司资金链,全员被迫离职,现在需要一份iOS开发的工作,杭州南京合肥的都可以。对我感兴趣的可以私聊我 0.0。谢谢~~~
一、NSOperation和NSOperationQueue介绍
- NSOperation: 操作(任务)
- NSOperationQueue: 操作队列(队列):分为主队列和自定义队列,是用来存放操作的队列,遵循FIFO(先进先出)的原则。通过最大并发数控制串行和并发。
- 实际上NSOperation和NSOperationQueue是OC语言基于GCD更高一层封装
- 使用起来比GCD更加的简单
- 提供了一些用GCD不好实现的功能
- 和GCD一样,我们不必去关心线程,以及线程的生命周期
- NSOperation是一个抽象的类,我们不能够直接去使用NSOperation,把NSOperation当作父类,起到约束子类的作用 ,然后通过去实现其子类来实现功能
- NSOperation的子类
- 子类 NSInvocationOperation
- 子类 NSBlockOperation
- 自定义继承自 NSOperation 的子类,通过实现内部相应的方法来封装操作。
- 一般情况下,通过NSOperation和NSOperationQueue实现的都是异步操作。
二、NSOperation和NSOperationQueue使用
- 通过子类NSInvocationOperation去执行线程操作
- NSInvocationOperation继承自NSOperation,并拥有自己的一些方法
- start方法是父类NSOperation中的,所以无论是NSInvocationOperation还是NSBlockOperation执行的效果都是一样的。
start: 1.不回去开启新线程 回调用 main函数 2.更新操作的状态
// 1. 调用start方法
// 创建操作
NSInvocationOperation *op = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(demo) object:nil];
NSLog(@"%d",op.finished);
//start: 1.不回去开启新线程 回调用 main函数
// 2.更新操作的状态
[op start];
NSLog(@"%d",op.finished);
// 2. 将操作添加到操作队列中
NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(demo) object:nil];
NSOperationQueue *opQueue = [[NSOperationQueue alloc]init] ;
// addOperation需要添加NSOperation类的实例化对象,但是这里添加NSInvocationOperation的实例化对象,是因为父类的指针可以指向子类
[opQueue addOperation:op1];
-(void)demo{
NSLog(@"123 = %@",[NSThread currentThread]);
}
通过start方法运行的结果:没开新线程,在主线程上面去执行
0
123 = <NSThread: 0x600001faae40>{number = 1, name = main}
1
通过:添加到NSOperationQueue队列上面之后,开启新线程
123 = <NSThread: 0x600001fefd00>{number = 3, name = (null)}
- 通过子类NSBlockOperation去执行线程操作
- 调用start方法
NSBlockOperation *blockOP = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"initNSBlockOperation = %@",[NSThread currentThread]);
}] ;
// 通过start方法
// 和NSInvocationOperation中的效果一样,因为start是父类NSOperation的方法
[blockOP start] ;
效果和NSInvocationOperation一样,不会开启新线程,在主线程上执行。
<NSThread: 0x6000008c2480>{number = 1, name = main}
- 添加到其他队列中
- 通过addExecutionBlock添加额外了操作
NSOperationQueue *queue = [[NSOperationQueue alloc]init] ;
NSBlockOperation *blockOP = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"initNSBlockOperation = %@",[NSThread currentThread]);
}];
// 添加额外的操作
[blockOP addExecutionBlock:^{
NSLog(@"addExecutionBlock = %@",[NSThread currentThread]);
}];
// 父类的指针可以指向子类
[queue addOperation:blockOP];
都是默认最大并发数为-1的时候
initNSBlockOperation = <NSThread: 0x6000037596c0>{number = 3, name = (null)}
addExecutionBlock = <NSThread: 0x60000374b040>{number = 4, name = (null)}
- 只通过NSOperationQueue去实现
- 一般我们都回去定义全局的NSOperationQueue对象
@property(nonatomic,strong)NSOperationQueue *queue;
...
-(NSOperationQueue *)queue{
if (_queue == nil) {
_queue = [[NSOperationQueue alloc]init];
// self.queue.maxConcurrentOperationCount =2;
}
return _queue;
}
...
for (int i = 0; i < 10; i++) {
[self.queue addOperationWithBlock:^{
NSLog(@"Demo3 = %d %@",i,[NSThread currentThread]);
}] ;
}
异步并发执行,开启新线程,并发执行
Demo3 = 2 <NSThread: 0x600003596680>{number = 5, name = (null)}
Demo3 = 1 <NSThread: 0x6000035882c0>{number = 3, name = (null)}
Demo3 = 0 <NSThread: 0x600003585d40>{number = 4, name = (null)}
Demo3 = 3 <NSThread: 0x600003585d00>{number = 6, name = (null)}
Demo3 = 5 <NSThread: 0x600003596680>{number = 5, name = (null)}
Demo3 = 6 <NSThread: 0x600003585d40>{number = 4, name = (null)}
Demo3 = 4 <NSThread: 0x6000035882c0>{number = 3, name = (null)}
Demo3 = 7 <NSThread: 0x600003585d00>{number = 6, name = (null)}
Demo3 = 8 <NSThread: 0x600003596680>{number = 5, name = (null)}
Demo3 = 9 <NSThread: 0x6000035882c0>{number = 3, name = (null)}
- 线程之间的通信
通过[NSOperationQueue mainQueue]回到主线程中
[self.queue addOperationWithBlock:^{
//异步下载
// 获取当前的队列
[NSOperationQueue currentQueue];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// 回到主线程来执行操作 更新UI
}];
}];
- 设置线程的最大并发数
通过maxConcurrentOperationCount属性来实现最大并发数- 当maxConcurrentOperationCount = 1 的时候,为串行执行,大于 1 为并发执行。
self.queue.maxConcurrentOperationCount =2; // 一般在懒加载中写
for (int i = 0; i< 10 ; i++) {
[self.queue addOperationWithBlock:^{
NSLog(@"%d=%@",i,[NSThread currentThread]);
}];
}
// 队列中的操作数
[self.queue operationCount];
1=<NSThread: 0x600003367680>{number = 4, name = (null)}
0=<NSThread: 0x600003369a00>{number = 3, name = (null)}
3=<NSThread: 0x600003367680>{number = 4, name = (null)}
2=<NSThread: 0x600003367b80>{number = 5, name = (null)}
4=<NSThread: 0x600003367680>{number = 4, name = (null)}
5=<NSThread: 0x600003367b80>{number = 5, name = (null)}
6=<NSThread: 0x600003367680>{number = 4, name = (null)}
7=<NSThread: 0x600003367b80>{number = 5, name = (null)}
8=<NSThread: 0x600003367680>{number = 4, name = (null)}
9=<NSThread: 0x600003367b80>{number = 5, name = (null)}
- 操作的优先级
- 优先级是先对的,只能说优先级高的操作,被执行的几率会大,并不代表先执行谁后执行谁。
NSBlockOperation *bOp1 = [NSBlockOperation blockOperationWithBlock:^{
for (int i=0; i<10; i++) {
NSLog(@"bOp1 %d %@",i,[NSThread currentThread]);
}
}];
/* 优先级由高到低
NSQualityOfServiceUserInteractive = 0x21,
NSQualityOfServiceUserInitiated = 0x19,
NSQualityOfServiceUtility = 0x11,
NSQualityOfServiceBackground = 0x09,
NSQualityOfServiceDefault = -1
*/
bOp1.qualityOfService = NSQualityOfServiceUserInteractive;
[self.queue addOperation:bOp1];
NSBlockOperation *bOp2 = [NSBlockOperation blockOperationWithBlock:^{
for (int i=0; i<10; i++) {
NSLog(@"bOp2 %d %@",i,[NSThread currentThread]);
}
}];
[self.queue addOperation:bOp2];
bOp1 0 <NSThread: 0x600001a6a140>{number = 3, name = (null)}
bOp2 0 <NSThread: 0x600001a611c0>{number = 4, name = (null)}
bOp2 1 <NSThread: 0x600001a611c0>{number = 4, name = (null)}
bOp1 1 <NSThread: 0x600001a6a140>{number = 3, name = (null)}
bOp1 2 <NSThread: 0x600001a6a140>{number = 3, name = (null)}
bOp2 2 <NSThread: 0x600001a611c0>{number = 4, name = (null)}
bOp1 3 <NSThread: 0x600001a6a140>{number = 3, name = (null)}
bOp1 4 <NSThread: 0x600001a6a140>{number = 3, name = (null)}
bOp2 3 <NSThread: 0x600001a611c0>{number = 4, name = (null)}
bOp1 5 <NSThread: 0x600001a6a140>{number = 3, name = (null)}
bOp1 6 <NSThread: 0x600001a6a140>{number = 3, name = (null)}
bOp2 4 <NSThread: 0x600001a611c0>{number = 4, name = (null)}
bOp1 7 <NSThread: 0x600001a6a140>{number = 3, name = (null)}
bOp1 8 <NSThread: 0x600001a6a140>{number = 3, name = (null)}
bOp1 9 <NSThread: 0x600001a6a140>{number = 3, name = (null)}
bOp2 5 <NSThread: 0x600001a611c0>{number = 4, name = (null)}
bOp2 6 <NSThread: 0x600001a611c0>{number = 4, name = (null)}
bOp2 7 <NSThread: 0x600001a611c0>{number = 4, name = (null)}
bOp2 8 <NSThread: 0x600001a611c0>{number = 4, name = (null)}
bOp2 9 <NSThread: 0x600001a611c0>{number = 4, name = (null)}
- 监听操作完成
当操作完成之后执行再执行某操作
NSBlockOperation *bOp1 = [NSBlockOperation blockOperationWithBlock:^{
for (int i=0; i<5; i++) {
NSLog(@"bOp1 %d %@",i,[NSThread currentThread]);
}
}];
[self.queue addOperation:bOp1];
bOp1.completionBlock = ^{
NSLog(@"完成操作");
};
bOp1 0 <NSThread: 0x600003c98780>{number = 3, name = (null)}
bOp1 1 <NSThread: 0x600003c98780>{number = 3, name = (null)}
bOp1 2 <NSThread: 0x600003c98780>{number = 3, name = (null)}
bOp1 3 <NSThread: 0x600003c98780>{number = 3, name = (null)}
bOp1 4 <NSThread: 0x600003c98780>{number = 3, name = (null)}
完成操作
- 添加操作依赖
简单理解为,若B依赖A则等到A执行完之后才去执行B,也就是它们之间有了执行的顺序。
注意防止出现循环依赖
通过 addDependency方法实现
移除依赖 removeDependency
NSBlockOperation *bOp1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下载压缩包");
}];
NSBlockOperation *bOp2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"解压压缩包");
}];
NSBlockOperation *bOp3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"升级完成");
}];
// 操作依赖,等依赖前面的操作执行完成之后再去执行后面的操作
[bOp2 addDependency:bOp1];
[bOp3 addDependency:bOp2];
// 错误操作,可能会出现循环依赖
// [bOp1 addDependency:bOp3] ;
[self.queue addOperations:@[bOp1,bOp2] waitUntilFinished:NO];
// 操作依赖可以跨队列
[[NSOperationQueue mainQueue]addOperation:bOp3];
下载压缩包
解压压缩包
升级完成
- 队列的取消、暂停、恢复
设置暂停、恢复通过suspended 属性来实现
当我们访问读取suspended的时候用isSuspended属性
// 取消 当前执行的操作不会立即取消,会执行完毕,后续的操作才会取消
[self.queue cancelAllOperations];
// 暂停 当前执行的操作不会立即暂停,会执行完毕,后续的操作才会暂停
self.queue.suspended = YES;
// 恢复
self.queue.suspended = NO;
文章到这里就结束了,我还是有很多不懂的地方,若文中有错误内容,欢迎指正,谢谢🙏。
文章主要参考:
行走少年郎的iOS 多线程:『NSOperation、NSOperationQueue』详尽总结
求职广告:本人实习生,现在急需一份工作,杭州南京合肥的都可以。对我感兴趣的可以私聊我 0.0。谢谢~~~
网友评论