iOS开发 - 多线程实现方案之NSOperation篇
NSOperation简介
1.实现多线程编程步骤:
配合使用NSOperation和NSOperationQueue实现多线程编程,我们不用考虑线程的生命周期、同步、加锁等问题,如下:
- 先将需要执行的操作封装到一个NSOperation对象中
- 然后将NSOperation对象添加到NSOperationQueue中
- 系统会自动将NSOperation中封装的操作放到一条新线程中执行
2.NSOperation的子类:
NSOperation是个抽象类,并不具备封装操作的能力,必须使⽤它的子类,使用NSOperation⼦类的方式有3种:
- NSInvocationOperation
- NSBlockOperation
- 自定义子类继承NSOperation,实现内部相应的⽅法
封装操作到NSOperation对象中(步骤一)
1.NSInvocationOperation
- (void)invocationOperation { //封装操作(任务) //注意:默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作。只有将operation放到一个NSOperationQueue中,才会异步执行操作 NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(startExecute:) object:@"funky"]; [op1 start]; } - (void)startExecute:(NSString *)param { NSLog(@"-------线程:%@ ------ 参数:%@",[NSThread currentThread],param); //执行操作... }
2.NSBlockOperation
- (void)blockOperation { //注意:如果一个操作中的任务数量大于1,那么会开子线程并发执行任务,但不一定是子线程,有可能是主线程 NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"----- %@",[NSThread currentThread]); //执行操作... }]; NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"----- %@",[NSThread currentThread]); //执行操作... }]; [op1 addExecutionBlock:^{ //op1追加任务1... }]; [op1 addExecutionBlock:^{ //op1追加任务2... }]; [op start]; [op1 start]; }
添加到NSOperationQueue中(步骤二)
1.NSInvocationOperation对象添加到NSOperationQueue中
- (void)invocationOperationWithQueue { //1.封装操作(任务) NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(startExecute:) object:@"funky"]; //2.创建队列(主队列,非主队列) //主队列 : [NSOperationQueue mainQueue]; (同GCD的主队列,串行队列) //非主队列 : [[NSOperationQueue alloc]init]; (同时具备并发和串行的功能,默认是并发队列) NSOperationQueue *queue = [[NSOperationQueue alloc]init]; //3.把操作添加到队列中 (内部已经调用了 [op1 start]) [queue addOperation:op1]; } - (void)startExecute:(NSString *)param { NSLog(@"-------线程:%@ ------ 参数:%@",[NSThread currentThread],param); //执行操作... }
2.NSBlockOperation对象添加到NSOperationQueue中及简便方式
- (void)blockOperationWithQueue { NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"----- %@",[NSThread currentThread]); //执行操作... }]; NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"----- %@",[NSThread currentThread]); //执行操作... }]; //创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc]init]; //添加到队列中 [queue addOperation:op]; [queue addOperation:op1]; } //或简便方法 -(void)simpleWay{ //创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc]init]; [queue addOperationWithBlock:^{ NSLog(@"开子线程执行任务----%@",[NSThread currentThread]); }]; }
3.自定义子类继承NSOperation
#import "CustomOperation.h" @implementation CustomOperation //重写main方法,在main方法中 执行操作 //可以提高代码复用性 -(void)main { NSLog(@"----- %@",[NSThread mainThread]); } @end
- (void)customOperationWithQueue { CustomOperation *op = [[CustomOperation alloc]init]; NSOperationQueue *queue = [[NSOperationQueue alloc]init]; [queue addOperation:op]; }
NSOperation的其他用法
1.NSOperation系统的子类的取消,暂定操作
//开始执行任务 - (IBAction)startBtnClick:(UIButton *)sender { self.queue = [[NSOperationQueue alloc]init]; //maxConcurrentOperationCount 最大并发数(同一时间最多有多少条任务可以执行) // >1并发队列 =1串行队列 =0不执行任务 =-1默认,代表最大值,最大并发数不受限制 self.queue.maxConcurrentOperationCount = 1; NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ for (int i =0; i < 1000; i++) { NSLog(@"download1-----%@",[NSThread currentThread]); } }]; NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ for (int i =0; i < 1000; i++) { NSLog(@"download2-----%@",[NSThread currentThread]); } }]; NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ for (int i =0; i < 1000; i++) { NSLog(@"download3-----%@",[NSThread currentThread]); } }]; [self.queue addOperation:op1]; [self.queue addOperation:op2]; [self.queue addOperation:op3]; } //暂停执行任务 - (IBAction)stopBtnClick:(UIButton *)sender { //可恢复,不能暂停当前正处于执行状态的任务 [self.queue setSuspended:YES]; } //继续执行任务 - (IBAction)goOnBtnClick:(UIButton *)sender { [self.queue setSuspended:NO]; } //取消执行任务 - (IBAction)cancelBtnClick:(UIButton *)sender { //不可恢复 //该方法内部调用了所有operation的cancel方法 [self.queue cancelAllOperations]; }
2.自定义NSOperation的取消操作
//开始执行任务 - (IBAction)startBtnClick:(UIButton *)sender { self.queue = [[NSOperationQueue alloc]init]; self.queue.maxConcurrentOperationCount = 1; HSOperation *op = [[HSOperation alloc]init]; [self.queue addOperation:op]; } //取消执行任务 - (IBAction)cancelBtnClick:(UIButton *)sender { //不可恢复 //该方法内部调用了所有operation的cancel方法 [self.queue cancelAllOperations]; }
#import "HSOperation.h" @implementation HSOperation -(void)main { //3个耗时操作,但相当于一个任务 for (int i =0; i < 1000; i++) { //if (self.isCancelled) return; 写在这会耗费性能,不建议在这进行操作 NSLog(@"download1-----%@",[NSThread currentThread]); } //检测是否取消了操作 if (self.isCancelled) return; for (int i =0; i < 1000; i++) { NSLog(@"download2-----%@",[NSThread currentThread]); } if (self.isCancelled) return; for (int i =0; i < 1000; i++) { NSLog(@"download3-----%@",[NSThread currentThread]); } } @end
3.操作依赖及操作监听
-(void)addDependency{ NSOperationQueue *queue = [[NSOperationQueue alloc]init]; NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ //耗时操作1... NSLog(@"download1-----%@",[NSThread currentThread]); }]; NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ //耗时操作2... NSLog(@"download2-----%@",[NSThread currentThread]); }]; NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ //耗时操作3... NSLog(@"download3-----%@",[NSThread currentThread]); }]; NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{ //耗时操作4... NSLog(@"download4-----%@",[NSThread currentThread]); }]; //操作监听 op3.completionBlock = ^{ NSLog(@"download3下载完成了-----%@",[NSThread currentThread]); }; //操作依赖 [op1 addDependency:op2]; //op1 等待 op2执行后 在执行 [op2 addDependency:op4]; [op4 addDependency:op3]; // [op3 addDependency:op1]; 不能循环依赖 [queue addOperation:op1]; [queue addOperation:op2]; [queue addOperation:op3]; [queue addOperation:op4]; }
NSOperation线程间的通信
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSOperationQueue *queue = [[NSOperationQueue alloc]init]; NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ NSURL *url = [NSURL URLWithString:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1490335106967&di=7daac700f5a1425d58131134228ea9bc&imgtype=0&src=http%3A%2F%2Fsh.sinaimg.cn%2Fcr%2F2013%2F1204%2F533155851.jpg"]; NSData *imgData = [NSData dataWithContentsOfURL:url]; UIImage *image = [UIImage imageWithData:imgData]; NSLog(@"download---%@",[NSThread currentThread]); //回到主线程刷新UI [[NSOperationQueue mainQueue] addOperationWithBlock:^{ self.imageView.image = image; NSLog(@"UI---%@",[NSThread currentThread]); }]; }]; [queue addOperation:op]; }

浙公网安备 33010602011771号