iOS面试

iOS 多线程NSOperation

2022-05-24  本文已影响0人  YourSummer

一. 定义

NSOperation是苹果公司提供的一套多线程解决方案, 它是基于GCD 的更抽象的"面向对象"封装.

二. 对比GCD

三. 任务

任务就是在线程中执行的代码, 在GCD中表现形式是block, 在NSOperationshi是在其子类NSInvocationOperation, NSBlockOperation, 自定义子类中执行任务代码.

四. 队列

NSOperationQueue表示队列, 用来存放任务的队列

五. 基本使用

NSOperation是一个抽象类, 使用的时候必须子类化, 提供三种方式创建任务:

1. 使用子类NSInvocationOperation
NSInvocationOperation *invocationOpeartion = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOpeartion) object:nil];
    
// 如果没有添加到 NSOperationQueue, 则需要手动调用 start
[invocationOpeartion start];

/// 回调方法
- (void)invocationOpeartion {
    for (int i = 0; i < 5; i++) {
        sleep(2);
        NSLog(@"%d -- %@", i, NSThread.currentThread);
    }
}

注意: NSInvocationOperation单独使用时, 并没有开启新的线程, 任务都是在当前线程中执行

2. 使用子类NSBlockOperation
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        // 任务代码
    for (int i = 0; i < 5; i++) {
        sleep(2);
        NSLog(@"%d -- %@", i, NSThread.currentThread);
    }
}];
    
[blockOperation start];

注意: NSBlockOperation单独使用时, 并没有开启新的线程, 任务都是在当前线程中执行

NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
    // 任务代码
    for (int i = 0; i < 5; i++) {
        sleep(2);
        NSLog(@"%d -- %@", i, NSThread.currentThread);
    }
}];
    
[blockOperation addExecutionBlock:^{
    NSLog(@"addExecutionBlock1:%@", NSThread.currentThread);
}];
[blockOperation addExecutionBlock:^{
    NSLog(@"addExecutionBlock2:%@", NSThread.currentThread);
}];
[blockOperation addExecutionBlock:^{
    NSLog(@"addExecutionBlock3:%@", NSThread.currentThread);
}];
[blockOperation start];

在调用了addExecutionBlock方法添加了多组任务后,开启新的线程,任务是并发执行的,blockOperationWithBlock中的任务执行是否在当前的线程执行, 统一由系统调度.

3. 自定义继承自NSOperation的子类
@interface Operation : NSOperation

@end

@implementation Operation

-(void)main {
    if (!self.isCancelled) {
        for (int i = 0; i < 4; i++) {
            sleep(2);
            NSLog(@"%d==%@", i, NSThread.currentThread);
        }
    }
}

@end

// 使用:
Operation *op = [[Operation alloc] init];
[op start];

注意: 自定义的Operation并没有开启新的线程,任务的执行是在当前的线程中执行的。

六. 队列: NSOperationQueue

NSOperationQueue提供了主队列和自定义队列

1.添加任务到队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

// 方式1: 
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
    // 任务代码
    for (int i = 0; i < 5; i++) {
        sleep(2);
        NSLog(@"%d -- %@", i, NSThread.currentThread);
    }
}];
[queue addOperation:blockOperation];

// 方式2: 
[queue addOperationWithBlock:^{
    // 任务代码
    for (int i = 0; i < 5; i++) {
        sleep(2);
        NSLog(@"%d -- %@", i, NSThread.currentThread);
    }
}];


// 注意: 不需要调用NSBlockOperationstart方法

2.添加多个操作到队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

// 操作1
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
    // 任务代码
    for (int i = 0; i < 5; i++) {
        sleep(2);
        NSLog(@"%d -- %@", i, NSThread.currentThread);
    }
}];

// 操作2
NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperation) object:nil];

// 方式1:
[queue addOperation:blockOperation];
[queue addOperation:invocationOperation];

// 方式2:
// waitUntilFinished参数,如果传YES,则表示会等待队列里面的任务执行完成后才会往下执行,也就是会阻塞线程
[queue addOperations:@[blockOperation, invocationOperation] waitUntilFinished:true];

/// 回调方法
- (void)invocationOperation {
    for (int i = 0; i < 5; i++) {
        sleep(2);
        NSLog(@"%d -- %@", i, NSThread.currentThread);
    }
}

总结: waitUntilFinished参数,如果传YES,则表示会等待队列里面的任务执行完成后才会往下执行,也就是会阻塞线程

七. 同步&并发

NSOperationQueue有个一属性maxConcurrentOperationCount
maxConcurrentOperationCount 默认-1, 不做限制, 在子线程中执行任务
maxConcurrentOperationCount = 1, 队列中的任务会同步执行, 阻塞当前线程
maxConcurrentOperationCount > 1, 队列中的任务会并发执行, 开启子线程执行
maxConcurrentOperationCount值并不是表示并发执行的线程数量,而是在一个队列中能够同时执行的任务的数量。

八. NSOperation线程间的通讯, 子线程完成任务, 会主线程更新UI

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
    // 任务代码
    for (int i = 0; i < 5; i++) {
        sleep(2);
        NSLog(@"%d -- %@", i, NSThread.currentThread);
    }
    // 回主队列更新UI
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        NSLog(@"更新UI");
    }];
}];
[queue addOperation:blockOperation];

九. 任务的依赖关系

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
    // 任务代码
    NSLog(@"1");
    
}];

NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"2");
}];

NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"3");
}];

// 1依赖于2和3, 意思是在2和3都执行完后才会执行1;
[operation1 addDependency:operation2];
[operation1 addDependency:operation3];
// 将1的优先级设置最高
operation1.queuePriority = NSOperationQueuePriorityHigh;

[queue addOperations:@[operation1, operation2, operation3] waitUntilFinished:NO];
//log: 2 3 1

总结:
queuePriority不能取代依赖关系
queuePriority属性只对同一个队列有效

十.设置完成回调

NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
    // 任务代码
    NSLog(@"1");
}];

// 设置任务1完成的回调block
[operation1 setCompletionBlock:^{
        NSLog(@"任务1完成了");
}];

十一. 监听状态

上一篇 下一篇

猜你喜欢

热点阅读