NSOperation简介

1.实现多线程编程步骤:

配合使用NSOperation和NSOperationQueue实现多线程编程,我们不用考虑线程的生命周期、同步、加锁等问题,如下:

  •  先将需要执行的操作封装到一个NSOperation对象中
  •  然后将NSOperation对象添加到NSOperationQueue中
  •  系统会自动将NSOperation中封装的操作放到一条新线程中执行

2.NSOperation的子类:

NSOperation是个抽象类,并不具备封装操作的能力,必须使⽤它的子类,使用NSOperation⼦类的方式有3种:

  • NSInvocationOperation
  • NSBlockOperation
  • 自定义子类继承NSOperation,实现内部相应的⽅法

封装操作到NSOperation对象中(步骤一)

1.NSInvocationOperation

iOS多线程的使用场景有哪些 ios多线程nsoperation_Code

iOS多线程的使用场景有哪些 ios多线程nsoperation_i++_02

- (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);
    //执行操作...
}

NSInvocationOperation封装操作

2.NSBlockOperation

iOS多线程的使用场景有哪些 ios多线程nsoperation_Code

iOS多线程的使用场景有哪些 ios多线程nsoperation_i++_02

- (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];
}

NSBlockOperation封装及追加任务

添加到NSOperationQueue中(步骤二)

1.NSInvocationOperation对象添加到NSOperationQueue中

iOS多线程的使用场景有哪些 ios多线程nsoperation_Code

iOS多线程的使用场景有哪些 ios多线程nsoperation_i++_02

- (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);
    //执行操作...
}

View Code

2.NSBlockOperation对象添加到NSOperationQueue中及简便方式

iOS多线程的使用场景有哪些 ios多线程nsoperation_Code

iOS多线程的使用场景有哪些 ios多线程nsoperation_i++_02

- (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]);
    }];

}

View Code

3.自定义子类继承NSOperation

iOS多线程的使用场景有哪些 ios多线程nsoperation_Code

iOS多线程的使用场景有哪些 ios多线程nsoperation_i++_02

#import "CustomOperation.h"

@implementation CustomOperation

//重写main方法,在main方法中 执行操作
//可以提高代码复用性
-(void)main {
    
    NSLog(@"----- %@",[NSThread mainThread]);
    
}


@end

继承于NSOperation的自定义类.m

iOS多线程的使用场景有哪些 ios多线程nsoperation_Code

iOS多线程的使用场景有哪些 ios多线程nsoperation_i++_02

- (void)customOperationWithQueue {
    
    CustomOperation *op = [[CustomOperation alloc]init];
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    [queue addOperation:op];
}

使用CustomOperation

NSOperation的其他用法

1.NSOperation系统的子类的取消,暂定操作

iOS多线程的使用场景有哪些 ios多线程nsoperation_Code

iOS多线程的使用场景有哪些 ios多线程nsoperation_i++_02

//开始执行任务
- (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];
}

View Code

2.自定义NSOperation的取消操作

iOS多线程的使用场景有哪些 ios多线程nsoperation_Code

iOS多线程的使用场景有哪些 ios多线程nsoperation_i++_02

//开始执行任务
- (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];
}

View Code

iOS多线程的使用场景有哪些 ios多线程nsoperation_Code

iOS多线程的使用场景有哪些 ios多线程nsoperation_i++_02

#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

HSOperation.m

3.操作依赖及操作监听

iOS多线程的使用场景有哪些 ios多线程nsoperation_Code

iOS多线程的使用场景有哪些 ios多线程nsoperation_i++_02

-(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];
    
    
}

View Code

NSOperation线程间的通信

iOS多线程的使用场景有哪些 ios多线程nsoperation_Code

iOS多线程的使用场景有哪些 ios多线程nsoperation_i++_02

-(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];
    
}

View Code