iOS开发多线程网络———NSOperation&NSOperationQueue
iOS开发多线程网络———NSOperation&NSOperationQueue
一.NSOperation&NSOperationQueue
1.简介
多线程编程是防止主线程堵塞,增加运行效率等等的最佳方法。而原始的多线程方法存在很多的毛病,包括线程锁死等。在Cocoa中,Apple提供了NSOperation这个类,提供了一个优秀的多线程编程方法。是使用GCD实现的一套Object-C的API,是面向对象的线程技术,提供了一些在GCD中不容易实现的特性,如:限制最大并发数量,操作之间的依赖关系。
2. 队列及操作
(注:一旦将操作添加到队列,操作就会立即被调度执行)
NSInvocationOperation(调度操作)
(1)定义操作队列
2 self.myQueue = [[NSOperationQueue alloc]init];
(2)定义操作
2 - (void)operationAction:(id)obj
3 {
4 NSLog(@"%@ - obj : %@", [NSThread currentThread], obj);
5 }
(3)将操作添加到队列(定义操作并添加到队列)
2 NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationAction:) object:@(i)];
3 [self.myQueue addOperation:op];
提示:需要准备一个被调用的方法,并且能够接受一个参数
代码示例:
2
3 @interface LDViewController ()
4 @property (nonatomic, strong) NSOperationQueue *myQueue;
5 @end
6
7 @implementation LDViewController
8
9 - (void)viewDidLoad
10 {
11 [super viewDidLoad];
12 self.myQueue = [[NSOperationQueue alloc]init];
13 [self demoOP2];
14 }
15 - (void)demoOP:(id)obj
16 {
17 NSLog(@"%@ - %@", [NSThread currentThread], obj);
18 }
19
20 #pragma mark - NSOperation方法
21 #pragma mark - NSInvocationOP
22 - (void)demoOP2
23 {
24 //需要定义一个方法,能够接受一个参数
25 //使用起来和Block比不够灵活,不用调来调去
26 NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demoOP: ) object:@"Hello op"];
27 // [self.myQueue addOperation:op];
28 //在主线程中执行
29 [[NSOperationQueue mainQueue] addOperation:op];
30 }
4.NSBlockOperation(块操作)基本使用步骤
(1)定义操作并添加队列
(注:NSBlockOperation比NSInvocationOperation更加灵活)
NSBlockOperation(调度操作)
(1)定义操作并添加队列
2 NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
3 [self operationAction:@"Block Operation"];
4 }];
(2)将操作添加到队列
2 [self.myQueue addOperation:op];
代码示例1:
3 @interface LDViewController ()
4 @property (nonatomic, strong) NSOperationQueue *myQueue;
5 @end
6
7 @implementation LDViewController
8
9 - (void)viewDidLoad
10 {
11 [super viewDidLoad];
12 self.myQueue = [[NSOperationQueue alloc]init];
13 [self demoOPerationQueue];
14 }
15
16
17 #pragma mark - NSOperation方法
18 #pragma mark - NSBlockOperation
19
20 - (void)demoOPerationQueue
21 {
22 // NSBlockOperation *block = [NSBlockOperation blockOperationWithBlock:^{
23 // NSLog(@"%@",[NSThread currentThread]);
24 // }];
25 // 所有的自定义队列,都是在子线程中运行
26 // [self.myQueue addOperation:block];
27 //简化为:
28 [self.myQueue addOperationWithBlock:^{
29 NSLog(@"%@",[NSThread currentThread]);
30 }];
31
32 //在主线程中执行
33 [[NSOperationQueue mainQueue] addOperationWithBlock:^{
34 NSLog(@"%@",[NSThread currentThread]);
35 }];
36 }
37 @end
执行结果:
2 2014-06-17 17:52:30.856 NSOperation[11770:60b] <NSThread: 0x8c41530>{name = (null), num = 1}
注:示例1中如果是多个任务,不会顺序执行
示例背景:模拟 “下载图片”---->"修饰图片"---->"保存图片"---->"更新UI"是循序执行的
代码示例2
3 @interface LDViewController ()
4 @property (nonatomic, strong) NSOperationQueue *myQueue;
5 @end
6
7 @implementation LDViewController
8
9 - (void)viewDidLoad
10 {
11 [super viewDidLoad];
12 self.myQueue = [[NSOperationQueue alloc]init];
13 [self demoOp3];
14 }
15 #pragma mark - NSOperation方法
16 #pragma mark - 设置任务的执行循序
17 - (void)demoOp3
18 {
19 NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
20 NSLog(@"下载图片 %@",[NSThread currentThread]);
21 }];
22 NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
23 NSLog(@"修饰图片 %@",[NSThread currentThread]);
24 }];
25 NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
26 NSLog(@"保存图片 %@",[NSThread currentThread]);
27 }];
28 NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
29 NSLog(@"更新UI %@",[NSThread currentThread]);
30 }];
31
32
33 [self.myQueue addOperation:op1];
34 [self.myQueue addOperation:op2];
35 [self.myQueue addOperation:op3];
36 [self.myQueue addOperation:op4];
37 }
38 @end
执行结果:
2 2014-06-17 19:59:31.008 NSOperation[12766:3903] 更新UI <NSThread: 0xa207340>{name = (null), num = 5}
3 2014-06-17 19:59:31.008 NSOperation[12766:3507] 修饰图片 <NSThread: 0x8f397e0>{name = (null), num = 3}
4 2014-06-1719:59:31.008 NSOperation[12766:3803] 保存图片 <NSThread: 0xa207730>{name = (null), num = 2}
执行结果的顺序是乱的,而且每一次的执行结果都不一样
如果想按顺序执行在31行代码中加入代码如:
2 [op3 addDependency:op2];
3 [op4 addDependency:op3];
注意:如果再加一句[op1 addDependency:op4]; 会造成循环依赖
如果所有UI的更新需要在主线程上进行那么将36行代码改为如下代码:
[[NSOperationQueue mainQueue] addOperation:op4];
加入以上代码最终结果为:
2014-06-17 20:11:41.630 NSOperation[12840:3507] 修饰图片 <NSThread: 0x9914ef0>{name = (null), num = 3}
2014-06-17 20:11:41.631 NSOperation[12840:3507] 保存图片 <NSThread: 0x9914ef0>{name = (null), num = 3}
2014-06-17 20:11:41.645 NSOperation[12840:60b] 更新UI <NSThread: 0x8d25430>{name = (null), num = 1
2014-06-1720:11:41.645 NSOperation[12840:60b] 更新UI <NSThread: 0x8d25430>{name = (null), num = 1
总结:NSBlockOperation用Dependency依赖关系,执行顺序,可能会开多个,但是不会开太多,而且依赖关系是可以跨队列的。而GCD的串行队列,异步任务,只会开一个线程,从本质上来看,操作队列的性能会比GCD略低,不过,大多数情况下这点负面影响可以忽略不计,操作队列是并发编程的首选工具