03-iOS多线程 | NSOperation,NSOperationQueue

170 阅读2分钟

大神链接

简介

NSOperation,NSOperationQueue是在GCD基础上的封装,面向对象

基本使用

NSOperation是个抽象类,不能用来封装操作.只有使用它的子类来封装操作.有三种方式来封装操作

  1. 使用子类 NSInvocationOperation
  2. 使用子类 NSBlockOperation
  3. 自定义继承自 NSOperation 的子类,通过实现内部相应的方法来封装操作
1. NSInvocationOperation
  • 单独使用 NSInvocationOperation
#创建NSInvocationOperation
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:NULL];
#启动
[operation start];

⚠️ 单独使用NSInvocationOperation,而没有使用NSOperationQueue,并不会创建线程,只会在当前线程执行任务

2. 单独使用NSBlockOperation
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"%@",[NSThread currentThread]); // 当前线程
}];
[operation start];

⚠️ 同样单独使用NSBlockOperation,一样不会创建线程,只在当前线程执行

  • NSBlockOperation 使用addExecutionBlock,那么添加的block有可能会开辟新线程执行
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"%@",[NSThread currentThread]); // 当前线程
}];
    
[operation addExecutionBlock:^{
    NSLog(@"%@",[NSThread currentThread]); // 新线程
}];
    
[operation start];
3.自定义NSOperation有两种

可以通过重写 main 或者 start 方法 来定义自己的 NSOperation 对象。重写main方法比较简单,我们不需要管理操作的状态属性 isExecuting 和 isFinished。当 main 执行完返回的时候,这个操作就结束了 重写start可以参考这个

⚠️ 单独使用NSOperation一样只会在当前线程执行,不会创建新的线程

4.使用NSOperationQueue
  • 主队列,在主队列中的任务都会在主线程执行
NSOperationQueue *queue = [NSOperationQueue mainQueue];
  • 自定义队列创建方法,在自定义的队列中会在子线程执行任务
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
-(void)operationQueue
{
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    NSInvocationOperation *invOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:NULL];
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"%@",[NSThread currentThread]); // <NSThread: 0x600001ee98c0>{number = 5, name = (null)}
    }];
    
    [queue addOperation:invOperation];
    [queue addOperation:blockOperation];
    [queue addOperationWithBlock:^{
        NSLog(@"%@",[NSThread currentThread]); // <NSThread: 0x600001eac640>{number = 6, name = (null)}
    }];
}

-(void)run
{
    NSLog(@"%@",[NSThread currentThread]); // <NSThread: 0x600001ee8a40>{number = 3, name = (null)}
}
  • NSOperationQueue 控制串行,并发队列(maxConcurrentOperationCount为1时串行队列,不为1时并发队列)
-(void)operationQueue
{
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    queue.maxConcurrentOperationCount = 1; // 串行队列
    [queue addOperationWithBlock:^{
        NSLog(@"1 - %@",[NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"2 - %@",[NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"3 - %@",[NSThread currentThread]);
    }];
}
#打印
1 - <NSThread: 0x6000005401c0>{number = 6, name = (null)}
2 - <NSThread: 0x6000005401c0>{number = 6, name = (null)}
3 - <NSThread: 0x6000005401c0>{number = 6, name = (null)}
  • 依赖操作
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
NSBlockOperation *block01 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"1 - %@",[NSThread currentThread]);
}];
NSBlockOperation *block02 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"2 - %@",[NSThread currentThread]);
}];
NSBlockOperation *block03 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"3 - %@",[NSThread currentThread]);
}];
    
[block02 addDependency:block01];
[block03 addDependency:block02];
    
[queue addOperation:block01];
[queue addOperation:block02];
[queue addOperation:block03];
#打印
1 - <NSThread: 0x600001a8c480>{number = 6, name = (null)}
2 - <NSThread: 0x600001a8c480>{number = 6, name = (null)}
3 - <NSThread: 0x600001a8c480>{number = 6, name = (null)}
  • 线程通信
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
[queue addOperationWithBlock:^{
    NSLog(@"%@",[NSThread currentThread]); //<NSThread: 0x600000223180>{number = 5, name = (null)}
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        NSLog(@"%@",[NSThread currentThread]); //<_NSMainThread: 0x600000270800>{number = 1, name = main}
    }];
}];
  • 卖票案例
-(void)initSaleSiticket
{
    self.ticketCount = 20;
    __weak typeof(self) weakSelf = self;
    
    // A窗口卖票线程
    NSOperationQueue *saleWindowAQueue = [[NSOperationQueue alloc] init];
    saleWindowAQueue.maxConcurrentOperationCount = 1;
    saleWindowAQueue.name = @"A窗口";
    [saleWindowAQueue addOperationWithBlock:^{
        [weakSelf saleSicketAction];
    }];
    
    // B窗口卖票线程
    NSOperationQueue *saleWindowBQueue = [[NSOperationQueue alloc] init];
    saleWindowBQueue.maxConcurrentOperationCount = 1;
    saleWindowBQueue.name = @"B窗口";
    [saleWindowBQueue addOperationWithBlock:^{
        [weakSelf saleSicketAction];
    }];
    
}


-(void)saleSicketAction
{
    while (YES) {
        [self.lock lock];
        if (self.ticketCount > 0) {
            self.ticketCount--;
            NSLog(@"%@ : %ld",[NSThread currentThread].name,(long)self.ticketCount);
        } else {
            NSLog(@"票卖完了");
            break;
        }
        [self.lock unlock];
        [NSThread sleepForTimeInterval:1.0];
    }
}