Objective-C 线程 NSOperation

1.  NSOperation 的子类实现3种方式: 在UI线程中执行都是

 1. NSInvocationOperation
 2.  NSBlockOperation
 3.  自定义子类实现

 1. NSInvocationOperation:  通过代理实

-(void)touchesBegan1:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
 
    /**
    1. 第一个参数 : 目标对象
     第二个参数: 选择器,要调用的方法
     第三方参数: 方法要传递的参数
     */
    NSInvocationOperation* op = [[ NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil];
    // 启动操作
    [op start];
}

-(void)download{
    
    NSLog(@"%s-----%@---",__func__, [NSThread currentThread]);
}

 2.  NSBlockOperation: 通过代码块实现

-(void)touchesBegan1:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
 /** 2.NSBlockOperation
      *
     */
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        // 在主线程中执行
        // {number = 1, name = main}
        NSLog(@"2------%@",[NSThread currentThread]);
    }];
    
    //2.追加操作
    //在子线程中执行
    [op1 addExecutionBlock:^{
        //{number = 3, name = (null)}
        NSLog(@"3------%@",[NSThread currentThread]);
    }];
    [op1 addExecutionBlock:^{
        // {number = 8, name = (null)}
        NSLog(@"4------%@",[NSThread currentThread]);
    }];
    
    [op1 addExecutionBlock:^{
        // {number = 9, name = (null)}
        NSLog(@"5------%@",[NSThread currentThread]);
    }];
    
    
    //3.启动操作执行
    [op1 start];
}

 3.  自定义子类实现 : 通过重写 main 函数实现

XMGOperation.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface XMGOperation : NSOperation

@end

NS_ASSUME_NONNULL_END
==============================================
XMGOperation.m

#import "XMGOperation.h"

@implementation XMGOperation

 //  问题: 如果使用 1. NSInvocationOperation   2.  NSBlockOperation 和2个子类
// 代码 直接 卸载 block中,会非常冗余
// 这里 单独写在 一个类中
// 1. 高封装, 信息隐蔽
// 2. 复用性
- (void)main{
    
    // ....
    //  一万 行代码 .....
    // ----XMGOperation----<NSThread: 0x600002a9d9c0>{number = 1, name = main}
    NSLog(@"----XMGOperation----%@",[NSThread currentThread]); 
}

@end

调用: 

-(void)touchesBegan1:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
 XMGOperation*  op2= [[XMGOperation alloc] init];
    [op2 start];
}

2.  NSOperationQueue队列 +    NSOperation子类: 在子线程中执行都是,并发队列

1. NSOperationQueue队列 + NSInvocationOperation
2. NSOperationQueue队列 +   NSBlockOperation
3. NSOperationQueue队列  +  自定义子类实现 

1. NSOperationQueue队列 + NSInvocationOperation

-(void)touchesBegan2:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
  // NSOperationQueue 队列
    // 主队列: 凡是放在主队列中的任务都是在主线程中执行的    [NSOperationQueue mainQueue]
    // 非主要队列: 同时具备并发和串行的功能,默认是并发队列   [[NSOperationQueue alloc] init]]
    
    
    /**
      并发,在子线程中执行
     -[ViewController1 download3]--3---<NSThread: 0x600002aef440>{number = 6, name = (null)}---
    -[ViewController1 download2]--2---<NSThread: 0x600002ad0bc0>{number = 4, name = (null)}---
     -[ViewController1 download1]---1--<NSThread: 0x600002ae1180>{number = 7, name = (null)}---
     */
    // 1. 创建队列
    NSOperationQueue* queue = [[NSOperationQueue alloc ]init];
    
    // 2. 创建任务
    NSInvocationOperation* op1= [[NSInvocationOperation alloc]
                                 initWithTarget:self selector:@selector(download1) object:nil];
    
    NSInvocationOperation* op2= [[NSInvocationOperation alloc]
                                    initWithTarget:self selector:@selector(download2) object:nil];
    
    NSInvocationOperation* op3= [[NSInvocationOperation alloc]
                                    initWithTarget:self selector:@selector(download3) object:nil];
    // 3. 把任务加入队列
    [queue addOperation:op1];
    // 添加以后会自动调用 start 方法
    [queue addOperation:op2];
    [queue addOperation:op3];
    
}

-(void)download1{
    
    NSLog(@"%s---1--%@---",__func__, [NSThread currentThread]);
}
-(void)download2{
    
    NSLog(@"%s--2---%@---",__func__, [NSThread currentThread]);
}
-(void)download3{
    
    NSLog(@"%s--3---%@---",__func__, [NSThread currentThread]);
}

2. NSOperationQueue队列 +   NSBlockOperation

-(void)touchesBegan3:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    // 1. 创建队列
       NSOperationQueue* queue = [[NSOperationQueue alloc ]init];
       
    // 2. 封装操作
    NSBlockOperation* op1 = [NSBlockOperation blockOperationWithBlock:^{
         NSLog(@"%s---1--%@---",__func__, [NSThread currentThread]);
    }];
    
    NSBlockOperation* op2 = [NSBlockOperation blockOperationWithBlock:^{
           NSLog(@"%s---2--%@---",__func__, [NSThread currentThread]);
      }];
    
    NSBlockOperation* op3 = [NSBlockOperation blockOperationWithBlock:^{
           NSLog(@"%s---3--%@---",__func__, [NSThread currentThread]);
      }];
    
    [op3 addExecutionBlock:^{
        NSLog(@"%s---4--%@---",__func__, [NSThread currentThread]);
    }];
    
    // 3. 添加到队列操作
    [queue addOperation:op1];
    [queue addOperation:op2];
    [queue addOperation:op3];
    
    // 直接添加任务到队列,简写
    [queue addOperationWithBlock:^{
          NSLog(@"%s---5--%@---",__func__, [NSThread currentThread]);
    }];
    
    /**
     执行结果 :  并发,在子线程中执行
     {number = 4, name = (null)}---
     {number = 3, name = (null)}---
     {number = 6, name = (null)}---
     {number = 5, name = (null)}---
     */
}

3. NSOperationQueue队列  +  自定义子类实现 

-(void)touchesBegan4:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    // 1. 创建队列
          NSOperationQueue* queue = [[NSOperationQueue alloc ]init];
    
    XMGOperation* op1= [[XMGOperation alloc] init];
    
    [queue addOperation:op1];
    /**
         输出内容 :在子线程中 执行
      {number = 6, name = (null)}
     */
    
}

3.  NSOperationQueue队列 +   NSOperation子类 实现串行 任务

通过设置   queue.maxConcurrentOperationCount= 1; 设置任务串行执行,只开一个子线程

-(void)touchesBegan5:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    // 1. 创建队列
       NSOperationQueue* queue = [[NSOperationQueue alloc ]init];
    // 串行队列, 只开一个子线程
    // 什么是串行: 就是按照 1,2,3 任务依次 执行
    // -1 无限制 最大并发数
    queue.maxConcurrentOperationCount= 1;
    
    // 2. 封装操作
    NSBlockOperation* op1 = [NSBlockOperation blockOperationWithBlock:^{
         NSLog(@"%s---1--%@---",__func__, [NSThread currentThread]);
    }];
    
    NSBlockOperation* op2 = [NSBlockOperation blockOperationWithBlock:^{
           NSLog(@"%s---2--%@---",__func__, [NSThread currentThread]);
      }];
    
    NSBlockOperation* op3 = [NSBlockOperation blockOperationWithBlock:^{
           NSLog(@"%s---3--%@---",__func__, [NSThread currentThread]);
      }];
    
    
    // 3. 添加到队列操作
    [queue addOperation:op1];
    [queue addOperation:op2];
    [queue addOperation:op3];
}

4. 暂停队列中任务: 

(self.queue.suspended):  暂停任务 ,可以就行执行
[self.queue cancelAllOperations];  取消所有任务,不可恢复

 -(void)touchesBegan6:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    // 当值 为 YES的 时候回暂停, 为NO的时候恢复
    if(self.queue.suspended){  // 如果是暂停
        NSLog(@"恢复执行");
        self.queue.suspended= NO;
    }else{
        NSLog(@"暂停执行");
        self.queue.suspended=YES;
    }
    // 注意:如果 op2已经在执行,执行 self.queue.suspended=YES; 不会暂停op2
    // 而是等待op2 执行完毕以后暂停后面的 op3
  //   [self.queue cancelAllOperations];  // 取消不在执行了,不可逆的
    
}

- (IBAction)btn:(id)sender {
    // 1. 创建队列
         NSOperationQueue* queue = [[NSOperationQueue alloc ]init];
      // 串行队列, 只开一个子线程
      // 什么是串行: 就是按照 1,2,3 任务依次 执行
      // -1 无限制 最大并发数
      queue.maxConcurrentOperationCount= 1;
      
      // 2. 封装操作
      NSBlockOperation* op1 = [NSBlockOperation blockOperationWithBlock:^{
           [NSThread sleepForTimeInterval:2.0];
           NSLog(@"%s---1--%@---",__func__, [NSThread currentThread]);
      }];
      
      NSBlockOperation* op2 = [NSBlockOperation blockOperationWithBlock:^{
             [NSThread sleepForTimeInterval:2.0];
             NSLog(@"%s---2--%@---",__func__, [NSThread currentThread]);
        }];
      
      NSBlockOperation* op3 = [NSBlockOperation blockOperationWithBlock:^{
             [NSThread sleepForTimeInterval:2.0];
             NSLog(@"%s---3--%@---",__func__, [NSThread currentThread]);
        }];
      
      
      // 3. 添加到队列操作
      [queue addOperation:op1];
      [queue addOperation:op2];
      [queue addOperation:op3];
    
      self.queue= queue;
}

5. 暂停 自定义 子类实现

MGOperation.h 和  MGOperation.m

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface XMGOperation : NSOperation

@end

NS_ASSUME_NONNULL_END
===================================================
#import "XMGOperation.h"

@implementation XMGOperation

- (void)main{
    
    // ....
    //  一万 行代码 .....
    // ----XMGOperation----<NSThread: 0x600002a9d9c0>{number = 1, name = main}
    for(NSInteger i=0;i<100;i++){
        [NSThread sleepForTimeInterval:0.1];
        NSLog(@"1--%zd--%@",i,[NSThread currentThread]);
    }
    
    // 不建议 放在  for 循环中每次 都判断
    // 执行完一段 耗时操作以后,判断是已经 调用cancle 方法, 取消任务
    if(self.isCancelled){
        return;
    }
    
    
    for(NSInteger i=0;i<100;i++){
        [NSThread sleepForTimeInterval:0.1];
        NSLog(@"2--%zd--%@",i,[NSThread currentThread]);
    }
    if(self.isCancelled){
          return;
    }
    
    
    for(NSInteger i=0;i<100;i++){
        [NSThread sleepForTimeInterval:0.1];
        NSLog(@"3--%zd--%@",i,[NSThread currentThread]);
    }
    if(self.isCancelled){
          return;
      }

    
}

@end

调用: 

- (IBAction)btn:(id)sender {
    // 1. 创建队列
         NSOperationQueue* queue = [[NSOperationQueue alloc ]init];
      
    XMGOperation * op1 = [[XMGOperation alloc] init];
    
   [queue addOperation:op1];
    
    
    self.queue=queue;

}


-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    // 如果自定义operation 那么 无法取消任务 调用  cancelAllOperations,
    // 苹果官方建议,在main 中判断  是否已经 调用取消
    [self.queue cancelAllOperations];
    
}

6. NSOperation 操作依赖 , 类似 gcd 的栅栏 函数 

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
       // 1. 创建队列
       NSOperationQueue* queue = [[NSOperationQueue alloc ]init];
    
       NSOperationQueue* queue1 = [[NSOperationQueue alloc ]init];

    
       // 2. 封装操作
       NSBlockOperation* op1 = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"%s---1--%@---",__func__, [NSThread currentThread]);
       }];
       NSBlockOperation* op2 = [NSBlockOperation blockOperationWithBlock:^{
              NSLog(@"%s---2--%@---",__func__, [NSThread currentThread]);
         }];
       NSBlockOperation* op3 = [NSBlockOperation blockOperationWithBlock:^{
              NSLog(@"%s---3--%@---",__func__, [NSThread currentThread]);
         }];
    
    NSBlockOperation* op4 = [NSBlockOperation blockOperationWithBlock:^{
                NSLog(@"%s---4--%@---",__func__, [NSThread currentThread]);
           }];
       // 添加操作依赖
    [op2 addDependency:op1];  // 操作2 一定在 操作1 后面执行
    [op3 addDependency:op2];  // 操作3 一定在 操作2 后面执行
    op2.completionBlock=^(){
        NSLog(@"%@",@"op2已经完成了");  // 依赖监听
    };
    [op4 addDependency:op3];  // 操作4 一定在 操作3 后面执行,操作依赖可以跨队列
    
    
    
       // 3. 添加到队列操作
       [queue addOperation:op1];
       [queue addOperation:op2];
       [queue addOperation:op3];
    
       [queue1 addOperation:op4];
    /** 输出结果 :
     _block_invoke---1--
     _block_invoke---2--
    _block_invoke_3---3--
        op2已经完成了
     _block_invoke_4---4-
     */
    
}

7. NSOperation 线程之间通信

案例,下载单张图片
下载2张图片,图片合成

7.1. 下载单张图片

-(void)touchesBegan8:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    NSOperationQueue* queue = [[NSOperationQueue alloc ]init];
    
    NSBlockOperation* op1 = [NSBlockOperation blockOperationWithBlock:^{
               NSLog(@"%s---1--%@---",__func__, [NSThread currentThread]);
               NSURL* url= [NSURL URLWithString:@"http://wimg.spriteapp.cn/cropx/852x480/cutbimage/5ed5b653d19fd.jpg"];
                        // 2. 下载图片
               NSData* data= [NSData dataWithContentsOfURL:url];
                        // 3. 把 二进制图片 转化为图片
               UIImage* image= [UIImage imageWithData:data];
          //  4.  刷新UI
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            self.myImageView.image = image;
        }];
                      
         
         }];
    
    [queue addOperation:op1];
}

2. 下载2张图片,图片合成

@interface ViewController1 ()

@property(nonatomic,strong) NSOperationQueue* queue;

@property (weak, nonatomic) IBOutlet UIImageView *myImageView;

@property(nonatomic,strong) UIImage* image1;
@property(nonatomic,strong) UIImage* image2;


@end

@implementation ViewController1
// 图片合成
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    NSOperationQueue* queue = [[NSOperationQueue alloc ]init];
      
      NSBlockOperation* download1 = [NSBlockOperation blockOperationWithBlock:^{
                 NSLog(@"%s---1--%@---",__func__, [NSThread currentThread]);
                 NSURL* url= [NSURL URLWithString:@"http://wimg.spriteapp.cn/cropx/852x480/cutbimage/5ed5b653d19fd.jpg"];
                          // 2. 下载图片
                 NSData* data= [NSData dataWithContentsOfURL:url];
                          // 3. 把 二进制图片 转化为图片
                 UIImage* image= [UIImage imageWithData:data];
          self.image1=  image;
       }];
    
    NSBlockOperation* download2 = [NSBlockOperation blockOperationWithBlock:^{
                   NSLog(@"%s---2--%@---",__func__, [NSThread currentThread]);
                   NSURL* url= [NSURL URLWithString:@"http://img5.mtime.cn/mg/2019/06/27/224744.68512147_120X90X4.jpg"];
                            // 2. 下载图片
                   NSData* data= [NSData dataWithContentsOfURL:url];
                            // 3. 把 二进制图片 转化为图片
                   UIImage* image= [UIImage imageWithData:data];
        self.image2= image;
         }];
    [queue addOperation:download1];
    [queue addOperation:download2];
      
    
    NSBlockOperation *combie = [NSBlockOperation blockOperationWithBlock:^{
        
        UIGraphicsBeginImageContext(CGSizeMake(200, 200));
        
        [self.image1 drawInRect:CGRectMake(0, 0, 200, 100)];
        [self.image2 drawInRect:CGRectMake(0, 100, 200, 100)];
        
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        
        UIGraphicsEndImageContext();
        
        //刷新UI
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            self.myImageView.image = image;
            NSLog(@"%@----",[NSThread currentThread]);
        }];

    }];
      
    
       [combie addDependency:download1];
       [combie addDependency:download2];
    
       [queue addOperation:combie]; 
}
@end

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值