NSOperation

概念

  • NSOperation 是对GCD的封装
  • queue、Operation
  • NSOperation,NSOperationQueue,实现多线程并发

NSOperation 子类

NSOperation是抽象类,必须使用其子类。
三种方式:

  • NSInvocationOperation
  • NSBlockOperation
  • 自定义子类,继承NSOperation,实现内部应用方法

NSInvocationOPeration

//1.invacationOperation
//注意:在默认情况下,调用start方法后,并不会开启一条新的线程去执行操作,而是在当前线程同步执行操作;只有将NSOperation放到NSOperationQueue中,才会异步执行操作
-(void)invocationOperation
{
    NSInvocationOperation *ip = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(operation ) object:nil];
    [ip start];
//    [self performSelector:@selector(operation) withObject:nil];
}

NSInvocationOperation只有配合NSOperationQueue使用才能实现多线程编程
单独使用NSInvocationOperation不会开启线程,默认在当前线程(指执行该方法的线程)中同步指向

NSBlockOperation

和NSInvocationOperation相似,只是将方法替换成了Block,并可以使用addExecutionBlock追加任务
单独使用NSBlockOperation和NSInvocationOperation一样,默认在当前线程中同步执行
但是使用addExecutionBlock追加的任务是并发执行的,如果这个操作中的任务数量大于1,那么会开子线程并发执行任务,并且追加的任务不一定就是子线程,也有可能是主线程。所以上述中任务1、2、3执行是可期的,有序的,但是任务4、5、6是并发执行的,不可控的。

//2.blockOperation
//注意:只要NSBlockOperation封装的操作数大于1,就会开启新线程,异步执行
-(void)blockOperation
{
    // 创建操作
    NSBlockOperation *bp = [NSBlockOperation blockOperationWithBlock:^{
        //在主线程中完成
        NSLog(@"--1--%@",[NSThread currentThread]);
        }];
        //额外任务在子线程完成
    [bp addExecutionBlock:^{
        NSLog(@"--2--%@",[NSThread currentThread]);
    }];
    [bp start];

自定义子类,继承NSOperation

自定义一个继承自NSOperation的类RCOperation,在.m中重写main方法即可,main方法中就是要执行的操作.

  1. non concurrent operation 只需要重写一个 -main{}
  2. concurrent operation 需要实现 start,finished 两个method 和两个property asy,ex
// 自定义类
#import <Foundation/Foundation.h>
@interface PJXCustomOperation : NSOperation
@end
#import "PJXCustomOperation.h"
@implementation PJXCustomOperation
//在实现文件中实现-main方法
-(void)main
{
    NSLog(@"--1--%@",[NSThread currentThread]);
}
@end
//调用
-(void)customOperation
{
    PJXCustomOperation *cp = [[PJXCustomOperation alloc]init];
    [cp start];
}

NSOperationQueue

NSOperation中的两种队列

  • 主队列 通过mainQueue获得,凡是放到主队列中的任务都将在主线程执行,这点很重要!!!
  • 非主队列 直接alloc init出来的队列。非主队列同时具备了并发和串行的功能,通过设置最大并发数属性来控制任务是并发执行还是串行执行

NSOperationQueue与GCD

GCD队列形式:1)全局 2)主队列 3)串行(自己创建的) 4)并行队列(自己创建)

NSOperationQueue队列形式:1)主队列 2)自己创建的非主队列

GCD:

串⾏类型:create & 主队列

并发类型:create & 全局并发队列

NSOperation:

主队列: [NSOperationQueue mainQueue] 和GCD中的主队列⼀样,串⾏队列

⾮主队列: [[NSOperationQueue alloc]init] ⾮常特殊(同时具备并发和串⾏的功能)

 //默认情况下,⾮主队列是并发队列
    NSOperationQueue *operationQueue = [[NSOperationQueue alloc ]init];


// invocationOperation
    NSInvocationOperation *op = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(operation) object:nil];
    [operationQueue addOperation:op];
    创建的队列中的任务默认是异步执行的


// NSBlockOperation
    // 创建操作
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        //在主线程中完成
        NSLog(@"--1--%@",[NSThread currentThread]);
        }];
        //额外任务在子线程完成
    [op2 addExecutionBlock:^{
        NSLog(@"--2--%@",[NSThread currentThread]);
    }];
    [[operationQueue addOperation:op2];
//提供⼀个简便⽅法,使⽤Block直接添加任务
 //1)创建操作,2)添加操作到队列中
    [operationQueue addOperationWithBlock:^{
        NSLog(@"--2--%@",[NSThread currentThread]);
    }];

//自定义的Operation和NSOperationQueue组合:
-(void)operation{
    NSOperationQueue *operationQueue = [[NSOperationQueue alloc ]init];
    PJXCustomOperation *cp = [[PJXCustomOperation alloc]init];
    [operationQueue addOperation:cp];
}

Queue的其他操作

  • 设置最大并发数
    设置最⼤并发数量 maxConcurrentOperationCount
    /*
    同⼀时间最多有多少个任务可以执⾏
    串⾏执⾏任务!=只开⼀条线程 (线程同步)
    maxConcurrentOperationCount >1 那么就是并发队列
    maxConcurrentOperationCount == 1 那就是串⾏队列
    maxConcurrentOperationCount == 0 不会执⾏任务
    maxConcurrentOperationCount == -1 特殊意义 最⼤值 表示不受限制
    */
    queue.maxConcurrentOperationCount = 1;
  • 暂停恢复和取消
    setSupended
    cancelAlloperation
  • 操作依赖
    [opA addDependency:opB];
  • 操作的监听
    • (void (^)(void))completionBlock;
    • (void)setCompletionBlock:(void (^)(void))block;
  • 线程间通信
//2021/8/11 iOS中NSOperation详解 - 简书
//https://www.jianshu.com/p/cffd3ace0653 1/2
- (void)downloadImage{
 __block UIImage *image1;
 __block UIImage *image2;

 //1.创建队列
 NSOperationQueue *queue = [[NSOperationQueue alloc]init];
 //2.封装操作下载图⽚1
 NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{

    NSURL *url = [NSURL URLWithString:@"https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1H
    NSData *data = [NSData dataWithContentsOfURL:url];
    //拿到图⽚数据
    image1 = [UIImage imageWithData:data];
    }];

 //3.封装操作下载图⽚2
 NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
    NSURL *url = [NSURL URLWithString:@"https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1H
    NSData *data = [NSData dataWithContentsOfURL:url];

    //拿到图⽚数据
    image2 = [UIImage imageWithData:data];
    }];

 //4.合成图⽚
 NSBlockOperation *drawOp = [NSBlockOperation blockOperationWithBlock:^{
    //4.1 开启图形上下⽂
    UIGraphicsBeginImageContext(CGSizeMake(200, 200));

    //4.2 画image1
    [image1 drawInRect:CGRectMake(0, 0, 200, 100)];
    //4.3 画image2
    [image2 drawInRect:CGRectMake(0, 100, 200, 100)];
    //4.4 根据图形上下⽂拿到图⽚数据
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    // NSLog(@"%@",image);
    //4.5 关闭图形上下⽂
    UIGraphicsEndImageContext();

    //7.回到主线程刷新UI
    [[NSOperationQueue mainQueue]addOperationWithBlock:^{
    self.imageView.image = image;
    NSLog(@"刷新UI---%@",[NSThread currentThread]);
    }];
    }];
//5.设置操作依赖
[drawOp addDependency:op1];
[drawOp addDependency:op2];

 //6.添加操作到队列中执⾏
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:drawOp];
}

参考文献

iOS中NSOperation详解

posted @ 2021-10-21 18:41  嗯呐东子  阅读(99)  评论(0)    收藏  举报