多线程----NSOperation详解
简介
-
NSOpreation的作用
p 配合NSOperation和NSOperationQueue也能够实现多线程编程 -
NSOperation 和 NSOperationQueue实现多线程的具体步骤
p 先将需要执行的操作封装到一个NSOperation对象中
p 然后将NSOperation对象添加到NSOperationQueue队列中
p 系统会自动将NSOperationQueue中的NSOperation取出来
p 将取出的NSOperation封装的操作放到一条新线程中执行
NSOpreation的子类
-
NSOpreation是个抽象类,并不具备封装操作的能力,
-
使用NSOperation子类的方式有3种
pNSInvocationOperation
pNSBlockOperation
p 自定义子类继承NSOperation,实现内部相应的方法。
NSInvocationOperation
- 创建NSInvocationOperation对象
NSInvocationOperation *p =[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
- 调用start方法开始执行操作
-(void)start //一旦执行就会调用target的sel方法
- 注意
p 默认情况下,调用了start方法后并不会开启一条新线程去执行操作,而是在当前线程同步执行操作
p 只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperation:p];
NSBlockOperation
-
创建NSBlockOperation对象
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ //在主线程中执行 NSLog(@"%@",[NSThread currentThread]); }];
- 通过
- (void)addExecutionBlock:(void (^)(void))block;
方法添加更多的操作
//添加额外的任务(在子线程执行)
[op addExecutionBlock:^{
NSLog(@"----%@",[NSThread currentThread]);
}];
[op start];
- 注意: 只要NSBlockOperation封装的操作数大于1 ,就会异步执行操作
NSOperationQueue
- NSOperationQueue的作用
p NSOperation可以调用start方法来执行任务,但默认是同步执行的
p 如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作 - 添加操作到NSoperationQueue中
- (void)addOperation:(NSOperation *)op; - (void)addOperationWithBlock:(void (^)(void))block;
- (对比GCD)
- GCD的队列类型
- 并发队列
- 自己创建的
- 全局的
- 串行队列
- 主队列
- 自己创建的
- 并发队列
- NSOperationQueue的队列类型
- 主队列
- [NSoperationQueue mainQueue]
- 凡是添加到主队列中的任务,都会放到主线程中执行
- 非主队列(其他队列)
- [[NSOperationQueue alloc] init]
- 同时包含了串行、并行功能
- 添加到这种队列中的任务(NSOperation),就会被自动放到子线程中执行
- 主队列
- GCD的队列类型
-
示例代码
- (void)OperationQueue{ //创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //创建操作(任务) //创建NSInvocationOperation NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task1) object:nil]; NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task2) object:nil]; //创建NSBlockOperation NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"task3 ---- %@",[NSThread currentThread]); }]; [op3 addExecutionBlock:^{ NSLog(@"task4 ---- %@",[NSThread currentThread]); }]; [op3 addExecutionBlock:^{ NSLog(@"task5 ---- %@",[NSThread currentThread]); }]; [queue addOperation:op1];//内部会自动调 [op1 start]; [queue addOperation:op2];//内部会自动调 [op2 start]; [queue addOperation:op3];//内部会自动调 [op3 start]; } - (void)task1{ NSLog(@"task1----%@",[NSThread currentThread]); } - (void)task2{ NSLog(@"task2----%@",[NSThread currentThread]); }
- 自定NSOperation
p 可以创建一个继承自NSOperation的类,在类的.m文件中重写方法- (void)main;
将需要执行的任务写在main方法中,然后 创建队列,实例化自定义类,将实例添加到队列中,也可以开启新线程执行任务。
p 示例代码
- (void)lgjOperation{
//创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//创建自定义NSOperationQueue
LGJNSOperation *operation = [[LGJNSOperation alloc] init];
[queue addOperation:operation];//[operation start];
}
//自定义Operation类
//.h文件
#import <Foundation/Foundation.h>
@interface LGJNSOperation : NSOperation
@end
//.m文件
#import "LGJNSOperation.h"
@implementation LGJNSOperation
//
-(void)main{
NSLog(@"LGJNSOperation -- 下载图片---%@",[NSThread currentThread]);
}
@end
最大并发数
-
什么是并发数
p 同时执行的任务数
p 比如同时开三个线程,执行三个任务,最大并发数就是3 -
最大并发数的相关方法
- (NSInteger)maxConcurrentOperationCount; - (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
p 示例代码
//最大并发数 - (void)OperationQueue1{ //创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //设置最大并发数 //queue.maxConcurrentOperationCount = 2; queue.maxConcurrentOperationCount = 1;//变成了串行队列 [queue addOperationWithBlock:^{ NSLog(@"task1---%@",[NSThread currentThread]); }]; [queue addOperationWithBlock:^{ NSLog(@"task2---%@",[NSThread currentThread]); }]; [queue addOperationWithBlock:^{ NSLog(@"task3---%@",[NSThread currentThread]); }]; [queue addOperationWithBlock:^{ NSLog(@"task4---%@",[NSThread currentThread]); }]; }
队列的取消、暂停、恢复
- 取消队列的所有操作
提示:也可以调用NSOperation的- (void)cancel方法取消单个操作- (void)cancelAllOperations;
-
暂停和恢复队列
- (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列 - (BOOL)isSuspended;
-示例代码1
- (void)viewDidLoad { [super viewDidLoad]; [self OperationQueue]; } -(void)OperationQueue{ NSOperationQueue *queue = [[NSOperationQueue alloc] init]; queue.maxConcurrentOperationCount = 1;//设置为1就变成了串行队列 //当执行了[self.queue cancelAllOperations];已经开启的线程是刹不住车的(意思是会继续打印),没有开启的线程将不会开启 [queue addOperationWithBlock:^{ for (NSInteger i = 0; i<1000 ; i++) { NSLog(@"task1 - %zd- %@",i,[NSThread currentThread]); } }]; [queue addOperationWithBlock:^{ for (NSInteger i = 0; i<1000 ; i++) { NSLog(@"task2 - %zd- %@",i,[NSThread currentThread]); } }]; [queue addOperationWithBlock:^{ for (NSInteger i = 0; i<1000 ; i++) { NSLog(@"task3 - %zd- %@",i,[NSThread currentThread]); } }]; self.queue = queue; } -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ [self.queue cancelAllOperations]; }
-
示例代码2
#import "ViewController.h" #import "LGJOperation.h" @interface ViewController () @property(nonatomic,strong)NSOperationQueue *queue; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self OperationQueue]; } -(void)OperationQueue{ NSOperationQueue *queue = [[NSOperationQueue alloc] init]; queue.maxConcurrentOperationCount = 1;//设置为1就变成了串行队列 //开启一条线程 执行自定义operation任务,任务的具体内容封装在自定义类的main方法中 LGJOperation *op = [[LGJOperation alloc] init]; [queue addOperation:op]; self.queue = queue; } -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ [self.queue cancelAllOperations]; } //自定义operation .h文件 #import <Foundation/Foundation.h> @interface LGJOperation : NSOperation @end //.m文件 #import "LGJOperation.h" @implementation LGJOperation -(void)main{ for (NSInteger i = 0; i<5000 ; i++) { //也可以在这里终止 if (i == 4000) { if (self.cancelled) return; } NSLog(@"task1 - %zd- %@",i,[NSThread currentThread]); } //如果想要终止线程中的任务,需要人为的做判断 if (self.cancelled) return; for (NSInteger i = 0; i<1000 ; i++) { NSLog(@"task2 - %zd- %@",i,[NSThread currentThread]); } //可以在这里终止 if (self.cancelled) return; for (NSInteger i = 0; i<1000 ; i++) { NSLog(@"task3 - %zd- %@",i,[NSThread currentThread]); } } @end
-
示例代码2
- (void)viewDidLoad { [super viewDidLoad]; [self suspended]; } // - (void)suspended{ //创建队列 self.queue1 =[[NSOperationQueue alloc] init]; //设置最大并发数 self.queue1.maxConcurrentOperationCount = 1; [self.queue1 addOperationWithBlock:^{ [NSThread sleepForTimeInterval:2.0]; NSLog(@"task1----%@",[NSThread currentThread]); }]; [self.queue1 addOperationWithBlock:^{ [NSThread sleepForTimeInterval:2.0]; NSLog(@"task2----%@",[NSThread currentThread]); }]; [self.queue1 addOperationWithBlock:^{ [NSThread sleepForTimeInterval:2.0]; NSLog(@"task3----%@",[NSThread currentThread]); }]; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ if (self.queue1.isSuspended) { //恢复队列,继续执行 self.queue1.suspended = NO; }else{ // 暂停(挂起)队列,暂停执行 self.queue1.suspended = YES; } }
操作依赖
-
NSOperation之间可以设置依赖来保证执行顺序
p 比如一定要让操作A执行完以后,才能执行操作B,可以这么写 -
示例代码
- (void)viewDidLoad { [super viewDidLoad]; [self Dependency]; } //操作依赖 - (void)Dependency{ //创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSInvocationOperation *operation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run2:) object:@"1"]; NSInvocationOperation *operation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run2:) object:@"2"]; NSInvocationOperation *operation3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run2:) object:@"3"]; //设置依赖 [operation1 addDependency:operation2];//1 依赖于 2 [operation2 addDependency:operation3];//2 依赖于 3 [queue addOperation:operation1]; [queue addOperation:operation2]; [queue addOperation:operation3]; } - (void)run2:(NSString*)obj{ NSLog(@"[current thread]==%@---obj===%@",[NSThread currentThread],obj); }
-
可以在不同queue的NSOperation之间创建依赖关系
操作的监听
-
可以监听一个操作的执行完毕
- (void (^)(void))completionBlock; - (void)setCompletionBlock:(void (^)(void))block;
-
示例代码
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"task1 === %@",[NSThread currentThread]); }]; operation1.completionBlock = ^{ NSLog(@"监听任务一执行完没1"); }; // [operation1 setCompletionBlock:^{ // // NSLog(@"监听任务一执行完没2"); // }]; [queue addOperation:operation1];
-
-