iOS_多线程三:NSOperation的使用

2022-07-20 14:09:24 浏览数 (3)

目录

一、NSInvocationOperation

二、NSBlockOperation

三、NSOperationQueue

NSOperation 是一个抽象类,线程安全,不需要添加额外的锁

使用其子类:NSInvocationOperation 和 NSBlockOperation

1、NSInvocationOperation

一个对象,表示一个任务

默认在主线程中同步顺序执行,想要并行异步,需要搭配`NSOperationQueue`使用

同步/异步,通过设置最大并发数`maxConcurrentOperationCount`实现:1:串行 >=2:并行 默认:-1 异步(无穷大)

2、NSBlockOperation

一个对象,可以创建多个任务

blockOperationWithBlock 添加的任务默认在主线程中

addExecutionBlock 添加任务,会开启多个线程,并发执行

一、NSInvocationOperation

一个 NSInvocationOperation 对象表示一个任务,需要手动调用 start 开启。

代码语言:javascript复制
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(network:) object:@{@"name":@"moxiaohui"}];
[operation setName:@"moxiaoyan"];
[operation setCompletionBlock:^{ // 任务执行完成后在子线程中执行
  NSLog(@"Completion %@", [NSThread currentThread]);
}];
[operation start];
NSLog(@"是否阻塞主线程"); // 会

- (void)network:(NSDictionary *)info {
  NSLog(@"执行 operation %@ %@", [NSThread currentThread], info);
  sleep(2);
  NSLog(@"完成 operation");
}

// 执行结果:
// 执行 operation <NSThread: 0x600000c24040>{number = 1, name = main} {
    name = moxiaohui;
}
// 完成 operation
// 是否阻塞主线程
// Completion <NSThread: 0x600003139680>{number = 4, name = (null)}

从执行结果可以看得出来,默认是在主线程中执行的,而且会阻塞主线程。

若想实现异步并发,需要结合 NSOperationQueue 使用:

代码语言:javascript复制
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 设置最大并发数: 1:串行 >=2:并行  默认:-1(无穷大)
// 注意:设置的是队列里面最多能并发运行的操作任务个数,而不是线程个数, (另外开启线程的数量是由系统决定的,所以这个值具体表示什么?)
[queue setMaxConcurrentOperationCount:2];
// 将任务添加到队列中
[queue addOperation:operation];
NSLog(@"是否阻塞主线程");

// 执行结果:
// 是否阻塞主线程
// 执行 operation <NSThread: 0x6000005e44c0>{number = 5, name = (null)} {
    name = moxiaohui;
}

NSOperationQueue一些其他的属性和方法:

代码语言:javascript复制
// 可以设置特殊的先后执行顺序:addDependency
[operation2 addDependency:operation1]; // 添加依赖
[operation3 removeDependency:operation1]; // 移除依赖

[operation start];  // NSInvocationOperation alloc init 创建的需要手动开启
[operation cancel]; // 取消单个任务,只会对还未执行的任务有效
[operation waitUntilFinished]; // 阻塞当前线程,直到任务执行完毕后继续 (最好不要在主线程中等待,会阻塞)
// 观察任务状态:
[operation isReady];  // 是否就绪
[operation isExecuting]; // 是否正在执行中
[operation isFinished]; // 是否执行完毕
[operation isCancelled];  // 是否已取消
[operation isAsynchronous]; // 是否异步执行
[operation isConcurrent]; // 已废弃,用`isAsynchronous`
NSOperationQueuePriority priority = [operation queuePriority]; // 优先级
NSArray<NSOperation *> *dependencies = [operation dependencies]; // 依赖的任务数组

二、NSBlockOperation

代码语言:javascript复制
NSBlockOperation *block = [NSBlockOperation blockOperationWithBlock:^{ // 默认在主线程中
  NSLog(@"执行2 block %@", [NSThread currentThread]);
  sleep(1);
  NSLog(@"完成2 block");
}];

// 通过 addExecutionBlock 添加的任务,会开辟多个子线程
[block addExecutionBlock:^{
  NSLog(@"执行3 block %@", [NSThread currentThread]);
  sleep(1);
  NSLog(@"完成3 block");
}];
[block addExecutionBlock:^{
  NSLog(@"执行4 block %@", [NSThread currentThread]);
  sleep(3);
  NSLog(@"完成4 block");
}];
[block addExecutionBlock:^{
  NSLog(@"执行5 block %@", [NSThread currentThread]);
  sleep(2);
  NSLog(@"完成5 block");
}];
[block start];
NSLog(@"是否阻塞主线程"); // 会

// 执行结果:
// 执行3 block <NSThread: 0x600003a9cd80>{number = 5, name = (null)}
// 执行2 block <NSThread: 0x600003a982c0>{number = 6, name = (null)}
// 执行5 block <NSThread: 0x600003aced40>{number = 1, name = main}
// 执行4 block <NSThread: 0x600003a97740>{number = 3, name = (null)}
// 完成2 block
// 完成3 block
// 完成5 block
// 完成4 block
// 是否阻塞主线程

从执行结果可以看出来,任务一多,就不确定哪个任务会主线程中执行了,所以感觉还是用queue比较保险

三、NSOperationQueue

NSOperationQueue 操作队列,管理Operation对象,根据Operation开辟适量的线程

代码语言:javascript复制
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 设置最大并发数: 1:同步 >=2:异步  默认:-1(无穷大)
// 注意:设置的是队列里面最多能并发运行的操作任务个数,而不是线程个数, (另外开启线程的数量是由系统决定的,所以这个值具体表示什么?)
[queue setMaxConcurrentOperationCount:2];
// 将任务添加到队列中
[queue addOperation:operation];
NSLog(@"是否阻塞主线程");
[queue addOperation:block];
[queue addOperationWithBlock:^{
NSLog(@"执行6 %@", [NSThread currentThread]);
sleep(2);
NSLog(@"完成6");
}];
[queue addBarrierBlock:^{ // 队列中所有任务完成后执行
NSLog(@"all complete");
}];
[queue setSuspended:YES]; // 暂停队列
[queue setSuspended:NO];  // 继续队列
[queue cancelAllOperations]; // 取消所有任务
[queue waitUntilAllOperationsAreFinished]; // 阻塞当前线程,直到所有任务执行完毕后继续(最好不要在主线程中等待,会阻塞)

Demo github 地址

0 人点赞