NSOperation与NSOperationQueue的使用
1.NSOperation
NSOperation是苹果提供的一种多线程方案。与GCD相比,属于面向对象层面开发。
我们不能直接使用NSOperation,需要使用它的子类进行创建任务。
NSOperation系统提供的子类有:NSInvocationOperation、NSBlockOperation。我们也可以自己定义NSOperation,实现main方法。
1.1NSInvocationOperation
NSInvocationOperation使用比较简单,创建对象,调用会想的start方法即可。如下:
//阻塞当前线程,在当前线程执行
NSInvocationOperation *operaton = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
[operaton start];
run方法如下所示:
- (void)run {
NSLog(@"%@",[NSThread currentThread]);
}
1.2NSBlockOperation
NSBlockOperation首先创建对象,然后执行start方法,可以添加多个任务。添加的第一个任务会阻塞当前线程,addExecutionBlock添加的任务不会阻塞,会在子线程执行。
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
sleep(2);
//阻塞当前线程,在当前线程执行
NSLog(@"%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
//不阻塞当前线程,在子线程执行
NSLog(@"block 2 %@",[NSThread currentThread]);
}];
[operation start];
1.3自定义NSOperation子类
自定义NSOperation子类,实现main方法,把任务代码写在main方法即可,自定义也会阻塞当前线程执行。代码如下:
@interface ESCOperation : NSOperation
@end
@implementation ESCOperation
- (void)main{
NSLog(@"%@",[NSThread currentThread]);
}
@end
调用如下:
ESCOperation *operation = [[ESCOperation alloc] init];
//阻塞当前线程执行
[operation start];
2.NSOperationQueue
NSOperationQueue是操作队列,和GCD的queue有些类似,可以往NSOperationQueue队列中添加NSOperation,有自定义的NSOperationQueue对象,也可以获取主线程NSOperationQueue对象,往主线程NSOperationQueue对象中添加任务,任务则在主线程执行,同时我们可以设置任务完成回调,监听任务完成情况,用法如下:
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
//子线程执行
NSLog(@"%@",[NSThread currentThread]);
}];
[operation setCompletionBlock:^{
//任务完成调用的方法
NSLog(@"completion %@",[NSThread currentThread]);
}];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
也可以直接添加block,如下:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
NSLog(@"3 %@",[NSThread currentThread]);
}];
获取主线程NSOperationQueue对象,添加任务
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
//主线程执行
NSLog(@"%@",[NSThread currentThread]);
}];
[operation setCompletionBlock:^{
//子线程执行
NSLog(@"completion %@",[NSThread currentThread]);
}];
NSOperationQueue *queue = [NSOperationQueue mainQueue];
[queue addOperation:operation];
NSOperationQueue提供了addBarrierBlock方法,保证任务的独立执行,方法如下:
/// @method addBarrierBlock:
/// @param barrier A block to execute
/// @discussion The `addBarrierBlock:` method executes the block when the NSOperationQueue has finished all enqueued operations and
/// prevents any subsequent operations to be executed until the barrier has been completed. This acts similarly to the
/// `dispatch_barrier_async` function.
- (void)addBarrierBlock:(void (NS_SWIFT_SENDABLE ^)(void))barrier API_AVAILABLE(macos(10.15), ios(13.0), tvos(13.0), watchos(6.0));
当我们有如下任务时,可使用该方法
image.png
代码如下:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
NSLog(@"任务1 %@",[NSThread currentThread]);
sleep(2);
}];
[queue addOperationWithBlock:^{
NSLog(@"任务2 %@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"任务3 %@",[NSThread currentThread]);
}];
[queue addBarrierBlock:^{
NSLog(@"任务4 %@",[NSThread currentThread]);
sleep(1);
}];
[queue addOperationWithBlock:^{
NSLog(@"任务5 %@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"任务6 %@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"任务7 %@",[NSThread currentThread]);
}];
我们可以设置队列的最大并发数,属性如下:
@property NSInteger maxConcurrentOperationCount;
设置为0时不执行任务。
我们也可以设置优先级,包括NSOperation对象和NSOperationQueue对象,属性如下:
typedef NS_ENUM(NSInteger, NSQualityOfService) {
NSQualityOfServiceUserInteractive = 0x21,
NSQualityOfServiceUserInitiated = 0x19,
NSQualityOfServiceUtility = 0x11,
NSQualityOfServiceBackground = 0x09,
NSQualityOfServiceDefault = -1
} API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));
@property NSQualityOfService qualityOfService API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));
可以暂停(继续)当前后续任务的执行:
@property (getter=isSuspended) BOOL suspended;
可以取消所有后续任务:
- (void)cancelAllOperations;
当我们有任务1和任务2,且任务1必须依赖任务2,意思就是说任务1必须等任务2执行完毕后才能执行,可以设置任务间的依赖来实现此功能。代码如下:
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
//子线程执行
NSLog(@"operation1 %@",[NSThread currentThread]);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
//子线程执行
NSLog(@"operation2 %@",[NSThread currentThread]);
}];
//operation1依赖operation2的执行,operation1必须在operation2执行完毕后再执行
[operation1 addDependency:operation2];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation1];
[queue addOperation:operation2];