在 iOS 中并发编程除了经常使用的 GCD 外还可以使用 NSOperation。与 GCD 相比 NSOperation 是面向对象的,所以更加易于使用,而且 NSOperation 包含了一些 GCD 较难实现的功能,也是苹果推荐的方式。
NSOperation 的主要使用方式就是将操作添加到队列中,而 NSOperation 本身是个抽象类,其只有方法声明并没有实现,所以我们需要使用其子类来创建操作
# 创建操作
NSOperation 创建的操作默认都是异步执行的,可以通过调用 start
方法在当前线程立即执行操作
# 使用 NSInvocationOperation 创建
下面的例子中 demo
是一个普通的方法,NSInvocationOperation 只能在 Objective-C 中使用,Swift 已经移除了这种方法
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo) object:nil];
// 在当前线程立即执行操作
[operation start];
2
3
# 使用 NSBlockOperation 创建
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
// 操作
}];
2
3
let operation = BlockOperation {
// 操作
}
2
3
我们可以通过 addExecutionBlock
给 NSBlockOperation 添加多个操作,这多个操作是异步执行的
[operation addExecutionBlock:^{
// 操作
}];
2
3
operation.addExecutionBlock {
// 操作
}
2
3
# 变更操作优先级
我们可以通过设置 queuePriority
设置操作的优先级,通过设置 qualityOfService
设置操作的服务质量即系统分配资源的数量
operation.queuePriority = NSOperationQueuePriorityHigh;
operation.qualityOfService = NSOperationQualityOfServiceUserInteractive;
2
operation.queuePriority = .high
operation.qualityOfService = .userInteractive
2
# 操作完成回调
我们可以给操作设置回调函数,可以在操作执行完毕时执行
[operation setCompletionBlock:^{
// 操作结束时回调
}];
2
3
operation.completionBlock = {
// 操作结束时回调
}
2
3
# 创建队列
我们可以通过 NSOperationQueue 创建队列,将操作放入队列中运行。队列默认是并行的,我们可以通过将最大并发数设置为 1 来让队列变为串行
// 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 向队列添加一个操作
[queue addOperation:operation];
2
3
4
// 创建队列
let queue = OperationQueue()
// 向队列添加一个操作
queue.addOperation(operation)
2
3
4
对于 NSBlockOperation 我们可以通过下面的方式直接向队列添加操作而无需单独创建
// 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 向队列添加一个操作
[queue addOperationWithBlock:^{
// 操作
}];
2
3
4
5
6
// 创建队列
let queue = OperationQueue()
// 向队列添加一个操作
queue.addOperation {
// 操作
}
2
3
4
5
6
# 主队列
我们可以通过下面的方式获得主队列,主队列是串行队列
NSOperationQueue *queue = [NSOperationQueue mainQueue];
let queue = OperationQueue.main
# 最大并发数
我们可以通过设置队列的 maxConcurrentOperationCount
参数来设置最大并发数,当该值设置为 1 时队列将以串行方式运行
queue.maxConcurrentOperationCount = 1
queue.maxConcurrentOperationCount = 1
# 队列的暂停、继续与取消
我们只能暂停与取消队列中还未执行的操作,正在执行的操作不受影响
# 队列暂停
queue.suspended = YES;
queue.isSuspended = true
注意
如果先暂停队列,再添加操作到队列,队列不会调度添加的操作。所以在暂停队列之前要判断队列中有没有任务,如果没有任务就不暂停队列。
# 队列继续
queue.suspended = NO;
queue.isSuspended = false
# 队列取消
[queue cancelAllOperations];
queue.cancelAllOperations()
# 操作依赖
如果一个操作需要另一个操作先完成则可以通过 addDependency
设置依赖。添加依赖需要在添加到队列前执行
NSBlockOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{
}];
NSBlockOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{
}];
// A 依赖于 B 先执行
[operationA addDependency:operationB];
2
3
4
5
6
let operationA = BlockOperation {
}
let operationB = BlockOperation {
}
// A 依赖于 B 先执行
operationA.addDependency(operationB)
2
3
4
5
6
注意
不能循环建立操作间依赖关系,否则队列不调度操作执行