NSOperation/NSOperationQueue
参考链接:http://www.cocoachina.com/ios/20151201/14517.html
- NSOperationQueue本身由Grand Central Dispatch队列支持
- 由于NSOperation的许多好处来自NSOperationQueue,因此几乎总是优先将操作添加到队列而不是直接调用start。
- 依赖关系是 operation 自身的状态,也就是说有依赖关系的 operations 可以处在不同的 NSOperationQueue 中。
NSInvocationOperation
在其他线程中单独使用子类 NSInvocationOperation,操作是在当前调用的其他线程执行的,并没有开启新线程。
- (void)operationTest {
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(NSInvocationOperationAction:) object:@"haha"];
[op start];
}
- (void)NSInvocationOperationAction:(NSString *)str {
NSLog(@"test result = %@",str);
}
NSBlockOperation
使用子类 NSBlockOperation,并调用方法 AddExecutionBlock: 的情况下,blockOperationWithBlock:方法中的操作 和 addExecutionBlock: 中的操作是在不同的线程中异步执行的。而且,这次执行结果中 blockOperationWithBlock:方法中的操作也不是在当前线程(主线程)中执行的。从而印证了blockOperationWithBlock: 中的操作也可能会在其他线程(非当前线程)中执行。
一般情况下,如果一个 NSBlockOperation 对象封装了多个操作。NSBlockOperation 是否开启新线程,取决于操作的个数。如果添加的操作的个数多,就会自动开启新线程。当然开启的线程数是由系统来决定的。
- (void)operationTest {
NSBlockOperation *block = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"test result = block operation");
NSLog(@"block 线程:%@",[NSThread currentThread]);
}];
[block addExecutionBlock:^{
NSLog(@"addExecutionBlock 开启新线程:%@",[NSThread currentThread]);
}];
[block start];
}
NSOperationQueue
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(NSInvocationOperationAction:) object:@"queue haha"];
NSBlockOperation *block = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"test queue result = block operation");
NSLog(@"开启新线程:%@",[NSThread currentThread]);
}];
[block addExecutionBlock:^{
NSLog(@"开启新线程:%@",[NSThread currentThread]);
}];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:op];
[queue addOperation:block];
[queue addOperationWithBlock:^{
NSLog(@"test queue add block");
NSLog(@"开启新线程:%@",[NSThread currentThread]);
}];
最大并发操作数:maxConcurrentOperationCount
- maxConcurrentOperationCount 默认情况下为-1,表示不进行限制,可进行并发执行。
- maxConcurrentOperationCount 为1时,队列为串行队列。只能串行执行。
- maxConcurrentOperationCount 大于1时,队列为并发队列。操作并发执行,当然这个值不应超过系统限制,即使自己设置一个很大的值,系统也会自动调整为 min{自己设定的值,系统设定的默认最大值}。
NSOperation 操作依赖
- - (void)addDependency:(NSOperation *)op; 添加依赖,使当前操作依赖于操作 op 的完成。
- - (void)removeDependency:(NSOperation *)op; 移除依赖,取消当前操作对操作 op 的依赖。
- @property (readonly, copy) NSArray<NSOperation *> *dependencies; 在当前操作开始执行之前完成执行的所有操作对象数组。
NSOperation 优先级
NSOperation 提供了queuePriority(优先级)属性,queuePriority属性适用于同一操作队列中的操作,不适用于不同操作队列中的操作。默认情况下,所有新创建的操作对象优先级都是NSOperationQueuePriorityNormal。但是我们可以通过setQueuePriority:方法来改变当前操作在同一队列中的执行优先级。
// 优先级的取值
typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
};
queuePriority 属性决定了进入准备就绪状态下的操作之间的开始执行顺序。并且,优先级不能取代依赖关系。有依赖关系的,等依赖执行完之后才进入就绪状态
自定义继承自 NSOperation 的子类
非并发操作
一般只覆写main
方法
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface TestOperation : NSOperation
@end
NS_ASSUME_NONNULL_END
@implementation TestOperation
- (void)main {
if (!self.isCancelled) {
for (int i = 0; i < 2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"1---%@", [NSThread currentThread]);
}
}
}
@end
并发操作
实现并发操作要点:
- 重写isConcurrent函数, 返回YES, 这个告诉系统各单位注意了我这个operation是要并发的.
- 重写start()函数.
- 重写isExecuting和isFinished函数
为什么在并发情况下需要自己来设定isExecuting和isFinished这两个状态量呢? 因为在并发情况下系统不知道operation什么时候finished, operation里面的task一般来说是异步执行的, 也就是start函数返回了operation不一定就是finish了, 这个你自己来控制, 你什么时候将isFinished置为YES(发送相应的KVO消息), operation就什么时候完成了.