阅读 41

NSOperation,NSOperationQueue 的使用

1. 简介

NSOperation,NSOperationQueue是基于GCD更高一层的封装,是苹果提供的一套针对多线程的解决方案。

NSOperation,NSOperationQueue的优点

  1. 可以添加代码块在操作完成后执行
  2. 添加操作依赖关系,方便控制操作的执行顺序
  3. 设置操作的优先级
  4. 很方便的取消一个操作的执行
  5. 使用KVO观察操作执行状态的更改(isFinished,isExecuting,isCancelled)

2.使用步骤

NSOperation需要配合NSOperationQueue来实现多线程。因为默认情况下NSOperation单独使用系统同步执行操作,配合使用NSOperationQueue能够更好的实现异步执行操作。

  1. 创建操作(将一个操作封装到NSOperation对象中)
  2. 创建队列 (创建NSOperationQueue对象)
  3. 将操作添加到队列中,并开始执行

3. 基本使用

NSoperation是一个抽象类,我们不能直接使用,需要使用它的子类来封装操作,这里有三种方式可以封装操作:

  1. 使用NSInvocationOperation
  2. 使用NSBlockOperation
  3. 自定义继承自NSoperation的子类

3.1 NSInvocationOperation的使用

打印结果:

从打印结果可以看出来,在没有使用NSOperationQueue,在主线程单独使用NSOperation的子类 NSInvocationOperation执行一个操作,是在当前线程执行的,并没有开启新线程。

在其他线程执行

执行结果:
可以看出来还是在当前线程执行的,并没有开启新线程

3.2 NSBlockOperation的使用

执行结果:
从执行结果看出还是在当前线程执行,没有开启新线程

NSBlockOperation提高addExecutionBlock增加额外操作的方法。这些操作可以在不同的线程中同时(并发)执行,只有当所有的操作执行完成才视为完成。 如果添加的操作很多的话,blockOperationWithBlock的操作也可能会在其他线程中(非当前线程)执行,这里是由系统决定的。可以使用addExecutionBlock多添加些操作:

执行结果:
从结果可以看到blockOperationWithBlock的操作也不是都在主线程(当前线程)执行的,从而验证了blockOperationWithBlock的操作也可能在其他线程执行。当操作的个数过多的情况下,系统会根据情况开启新线程执行,线程的数量是由系统决定的。

3.3 自定义继承自NSoperation的子类的使用

NSoperation的子类不能满足需要,我们可以通过自定义子类实现,通过重新main方法或者start方法来定义自己的operation对象,重写main方法比较简单。我们不需要管理操作的属性状态isFinished和isExecuting,当main执行完之后,操作也就执行完了。

执行的结果:
可以看出还是在当前线程执行,没有开启新的线程。

4. NSOperationQueue的使用

NSOperationQueue包含两种队列:主队列和自定义队列。自定义队列同时包含了串行和并发功能。 主队列: NSOperationQueue *queue = [NSOperationQueue mainQueue];

自定义队列: NSOperationQueue *queue = [[NSOperationQueue alloc]init];

执行的结果:
从结果可以看出通过addOperation将操作添加到队列中,是可以开启新线程的,并且并发执行。 通过addOperationWithBlock直接将操作添加到队列中。同样会开启新线程,并发执行。

NSOperationQueue控制串行和并发

通过控制最大操作并发数maxConcurrentOperationCount实行串行和并发

  • 默认为-1,表示不进行控制,可以并发执行
  • 为1时,队列为串行队列,只能串行执行
  • 大于1时,队列为并发队列,并发执行,这个值不能超过系统限制,即使设置的无穷大系统会取设置值和默认最大值的小值。

操作数1:
可以看出是按顺序执行的,一个操作完成执行下一个操作

操作数2,可以看出是并发执行的,一次执行两个操作,但是开启的线程数量是由系统决定的

NSOperation操作依赖

NSOperation可以通过操作依赖,控制操作的执行顺序。
添加依赖 - (void)addDependency:(NSOperation *)op;
移除依赖 - (void)removeDependency:(NSOperation *)op;
@property (readonly, copy) NSArray<NSOperation *> *dependencies;

添加依赖:

执行结果:
可以看出op执行完成之后op1才执行。

NSOperation优先级

@property NSOperationQueuePriority queuePriority;

queuePriority适用用同一操作队列的操作,不适用于不同操作队列的操作。优先级不能取代依赖关系,要控制操作顺序还是要使用依赖,会优先执行优先级高的。

NSOperation、NSOperationQueue 非线程安全可以通过加锁和解锁实现线程安全


注意:无论是操作或者是队列的暂停和取消都不是立即将当前的操作取消,而是等当前操作完成之后,不在往下执行。 暂停和取消的区别在于暂停的操作可以恢复,继续往下执行,取消的操作是不能恢复的,不能继续往下执行。

关注下面的标签,发现更多相似文章
评论