前言:

    前面学习了NSThread使用,今天学习一下apple提供的多线程解决方案NSOperation,NSOperation是基于GCD开发,相对于GCD来说可控性更强,并且可以加入操作依赖。

NSOperation

  NSOperation表示了一个独立的计算单元。作为一个抽象类,它给了它的子类一个十分有用而且线程安全的方式来建立状态、优先级、依赖性和取消等的模型。系统已经给我们封装了NSInvocationOperation和NSBlockOperation这两个实体类, 接下来看下这两个子类的使用,同样我们也可以通过自定义NSOperation。

NSInvocationOperation

//创建NSInvocationOperation操作对象,封装要执行的任务
    NSInvocationOperation *operation= [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(operationTask) object:nil];
    //设置任务优先级
    [operation setQualityOfService:NSQualityOfServiceUserInteractive];
    //设置任务优先级
    [operation setQueuePriority:NSOperationQueuePriorityHigh];
    //设置任务名称
    [operation setName:@"operation-1"];
    //启动执行任务
    [operation start];
    //取消执行任务
    [operation cancel];

然后我们来看下operationTask函数

-(void)operationTask
{
    [NSThread sleepForTimeInterval:2];
    NSLog(@"operationTask:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
}

运行结果:

ios nstimer 后台 ios nsoperation_ios nstimer 后台

 通过运行结果会发现,竟然执行在主线程中,所以使用这种方式是同步方式而非异步方式。

NSBlockOperation  

//创建NSBlockOperation操作对象
    NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{
           NSLog(@"operationTask:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    }];

    //添加操作
    [operation addExecutionBlock:^{
            NSLog(@"operationTask:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    }];

    //设置任务优先级
    [operation setQualityOfService:NSQualityOfServiceUserInteractive];
    //设置任务优先级
    [operation setQueuePriority:NSOperationQueuePriorityHigh];
    //设置任务名称
    [operation setName:@"operation-1"];
    //启动执行任务
    [operation start];
    //取消执行任务
    [operation cancel];

运行结果

ios nstimer 后台 ios nsoperation_优先级_02

通过运行结果会发现,第一个block运行在主线程中,第二block运行在子线程中,因此,NSBlockOperation只有在封装的操作数大于1时才会开启子线程执行,否则默认执行在主线程。

自定义NSOperation

  有时上述的连个子类不能满足我们的需求,需要我们自定义NSOperation,我们只需修改mian函数即可。

 XLTaskOperation.h

#import <Foundation/Foundation.h>

@interface XLTaskOperation : NSOperation

@property (nonatomic, copy) NSString *key;

@property (nonatomic, copy) void(^sucessBlock)(NSString *) ;

@end

XLTaskOperation.m

#import "XLTaskOperation.h"

@implementation XLTaskOperation

-(void)main
{
    NSLog(@"operationTask:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    NSMutableString *mutableString=[[NSMutableString alloc]initWithString:self.key];
    [mutableString appendString:@" from cache"];
    //回到主线程,通过block传递数据
    dispatch_async(dispatch_get_main_queue(), ^{
        if(self.sucessBlock){
            self.sucessBlock(mutableString);
        }
    });
}

@end

使用方式

XLTaskOperation *xlTaskOperation =[[XLTaskOperation alloc]init];
  xlTaskOperation.key=@"whoislcj";
  xlTaskOperation.sucessBlock=^(NSString * cache){
      NSLog(@"operationTask:%@ cache: %@",[NSThread currentThread],cache);
  };
  [xlTaskOperation start];

运行结果

ios nstimer 后台 ios nsoperation_主线程_03

同样也是默认运行在主线程中。

NSOperationQueue

 通过上面的三种方式生成NSOperation调用start函数,因为都是默认执行在主任务队列mainQueue中,所以才会执行在主线程中,如果采用下面这种方式都会执行在异步子线程中。

//创建NSOperationQueue
    NSOperationQueue * queue=[[NSOperationQueue alloc]init];
    //设置NSOperationQueue最大并发任务数
    queue.maxConcurrentOperationCount=3;

    NSInvocationOperation *operation1= [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(operationTask) object:nil];
    NSInvocationOperation *operation2= [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(operationTask) object:nil];

    NSBlockOperation *operation3=[NSBlockOperation blockOperationWithBlock:^{
        [NSThread sleepForTimeInterval:1];
         NSLog(@"operationTask:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
    }];

    [operation3 addExecutionBlock:^{
        [NSThread sleepForTimeInterval:1];
        NSLog(@"operationTask:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");        }];

    [queue addOperation:operation1];
    [queue addOperation:operation2];
    [queue addOperation:operation3];

    for (int i =0; i<9; i++) {
        [queue addOperationWithBlock:^{
            [NSThread sleepForTimeInterval:1];
            NSLog(@"operationTask:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO");
        }];
    }
operationTask函数同上,看下运行结果

ios nstimer 后台 ios nsoperation_优先级_04

因为上面设置了最大并行线程数为3,但是我实测却创建了4个线程,这点我有点不太理解,每次并行执行3个。

总结:

   简单学习了NSOperation的使用。