本质上是GCD的并发队列异步执行,是对GCD的面向对象的封装,是苹果大力推荐的并发技术

与GCD的对比:

  • GCD:
  • iOS 4.0 推出
  • 针对多核处理器做了优化的并发技术
  • 是C语言
  • 提供一次执行、延迟执行、调度组
  • 任务添加到队列(串行、并发、主队列、全局队列),并且指定执行任务的函数(同步、异步)
  • NSOperation:
  • iOS 2.0 推出
  • 底层是GCD
  • 面向对象
  • 提供最大并发线程、队列暂停继续、取消所有操作、指定操作之间的依赖关系
  • 操作添加到队列(并发),然后立即异步执行

NSOperation 是一个抽象类,继承NSObject

  • 特点:不能直接使用
  • 目的:定义子类共有属性和方法
  • 子类:
  • NSInvocationOperation
  • NSBlockOperation
1
2
3
4
5
6
7
8
9
10
11
12
- (void)demo1 {
NSInvocationOperation * op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadImage:) object:@"invocation"];
[op start];
}
- (void)downloadImage:(id)objc {
NSLog(@"%@ %@", [NSThread currentThread, objc]);
}

- (void)viewDidLoad {
[super viewDidLoad];
[self demo1];
}

使用队列

1
2
3
4
5
6
- (void)demo1 {
NSInvocationOperation * op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadImage:) object:@"invocation"];
NSOperationQueue * q =[[NSOperationQueue alloc] init];
// 添加到队列
[q addOperation: op]
}

NSBlockOperation

1
2
3
4
5
6
- (void)demo3 {
NSOperationQueue * q =[[NSOperationQueue alloc] init];
NSBlockOperation * op = [NSBlockOperation blockOperationWithBlock: ^{
NSLog(@"%@", [NSThread currentThread]);
}]
}

更简单的写法

1
2
3
4
5
6
- (void)demo4 {
NSOperationQueue * q =[[NSOperationQueue alloc] init];
[q addOperationWithBlock: ^{
NSLog(@"%@", [NSThread currentThread]);
}]
}

使用全局队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@interface ViewController()
// 先定义一个全局变量,然后用它指向一个队列
@property(nonacomic, strong) NSOperationQueue * opQueue;
@end

@implementation ViewController

// 懒加载
-(NSOperationQueue *)opQueue {
if(!_opQueue) {
_opQueue = [[NSOperationQueue alloc]init];
}
return _opQueue;
}

// 使用
- (void)demo5 {
[self.opQueue addOperationWithBlock: ^{
NSLog(@"%@", [NSThread currentNSThread]);
}];

// block operation
NSBlockOperation * op1 = [NSBlockOperation blockOperationWithBlock: ^{
NSLog(@"%@", [NSThread currentThread]);
}];
[self.opQueue addOperation: op1];

// invocation operation
NSInvocationOperation * op2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downloadImage:) object:@"invocation"];
[self.opQueue addOperation: op2];
}

@end

线程间的通讯,在子线程更新UI

1
2
3
4
5
6
7
8
9
- (void)demo6 {
[self.opQueue addOperationWithBlock: ^{
NSLog(@"耗时操作 %@", [NSThread currentThread]);
// 主线程更新UI,首先拿到主线程
[[NSOperationQueue mainQueue] AddOperationWithBlock: ^{
NSLog(@"UI操作 %@", [NSThread currentThread]);
}];
}];
}

最大并发数,iOS 8.0 开始无论使用GCD还是NSOperation都会开启很多子线程,iOS 7.0 以前,GCD通常只会开启5~6条线程

一般情况下,WIFI网络设置5、6,流量网络设置2、3

1
2
3
4
5
6
7
8
9
- (void)demo7 {
// 控制最大线程数量
self.opQueue.maxConcurrentOperationCount = 2;
for(int i = 0; i < 20; i++) {
[self.opQueue addOperationWithBlock: ^{
NSLog(@"%@", [NSThread currentThread]);
}];
}
}

暂停、继续

1
2
3
4
5
6
7
8
9
10
-(IBAction) pause {
// 判断队列是否挂起(暂停)
if(self.opQueue.isSuspended) {
NSLog(@"继续");
self.opQueue.suspended = NO;
} else {
NSLog(@"暂停");
self.opQueue.suspended = YES;
}
}

取消所有操作

1
2
3
4
- (IBAction) cancelAll {
NSLog(@"取消所有操作");
[self.opQueue cancelAllOperations];
}

依赖关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- (void) dependecy {
NSBlockOperation * op1 = [NSBlockOperation blockOperationWithBlock: ^{
NSLog(@"动作 1 %@", [NSThread currentThread]);
}];
NSBlockOperation * op2 = [NSBlockOperation blockOperationWithBlock: ^{
NSLog(@"动作 2 %@", [NSThread currentThread]);
}];
NSBlockOperation * op3 = [NSBlockOperation blockOperationWithBlock: ^{
NSLog(@"动作 3 %@", [NSThread currentThread]);
}];

// NSOperation 的依赖关系,op2依赖于op1,op3依赖于op2
[op2 addDependency: op1];
[op3 addDependency: op2];

// 添加到队列,waitUntilFinished是“是否等待”,会卡住当前线程
[self.opQueue addOperations:@[op1, op2, op3] waitUntilFinished:YES];

// 更新UI让主线程执行操作
[[NSOperationQueue mainQueue] addOperation:op3];

NSLog(@"运行至此");
}