iOS开发多线程网络———NSOperation&NSOperationQueue

iOS开发多线程网络———NSOperation&NSOperationQueue

一.NSOperation&NSOperationQueue 

1.简介

        多线程编程是防止主线程堵塞,增加运行效率等等的最佳方法。而原始的多线程方法存在很多的毛病,包括线程锁死等。在Cocoa中,Apple提供了NSOperation这个类,提供了一个优秀的多线程编程方法。是使用GCD实现的一套Object-C的API,是面向对象的线程技术,提供了一些在GCD中不容易实现的特性,如:限制最大并发数量,操作之间的依赖关系。

 

2. 队列及操作

NSOperationQueue有两种不同类型的队列:主队列和自定义队列
主队列运行在主线程上
自定义队列在后台执行
队列处理的任务是NSOperation的子类
(1)NSInvocationOperation
(2)NSBlockOperation
3.NSInvocationOperation基本使用步骤
(1)定义操作队列
(2)定义操作
(3)将操作添加到队列

  (注:一旦将操作添加到队列,操作就会立即被调度执行)

NSInvocationOperation(调度操作) 

      (1)定义操作队列 

1  //定义队列
2     self.myQueue = [[NSOperationQueue alloc]init];

     (2)定义操作

1     //定义操作 (操作调用的方法)
2 - (void)operationAction:(id)obj
3 {
4     NSLog(@"%@ - obj : %@", [NSThread currentThread], obj);
5 }

     (3)将操作添加到队列(定义操作并添加到队列)

1 //定义操作并添加到队列
2 NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationAction:) object:@(i)];
3 [self.myQueue addOperation:op];

提示:需要准备一个被调用的方法,并且能够接受一个参数 

代码示例:

 1 #import "LDViewController.h"
 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)定义操作并添加队列

(2)将操作添加到队列

   (注:NSBlockOperation比NSInvocationOperation更加灵活)

NSBlockOperation(调度操作)  

      (1)定义操作并添加队列  

1 //定义操作并添加到队列
2 NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
3     [self operationAction:@"Block Operation"];
4 }];

      (2)将操作添加到队列

 1    //将操作添加到队列
 2 [self.myQueue addOperation:op];

 

代码示例1:

 

  

 1 #import "LDViewController.h"
 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

 

 

 

 执行结果:

1 2014-06-17 17:52:30.837 NSOperation[11770:1303] <NSThread: 0x8e52d40>{name = (null), num = 2} 

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

 执行结果:

1 2014-06-17 19:59:31.008 NSOperation[12766:1303] 下载图片 <NSThread: 0x8c15f70>{name = (null), num = 4}
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} 

 2014-06-1719:59:31.008 NSOperation[12766:3803] 保存图片 <NSThread: 0xa207730>{name = (null), num = 2}

执行结果的顺序是乱的,而且每一次的执行结果都不一样

如果想按顺序执行在31行代码中加入代码如:

1 [op2 addDependency:op1];

2 [op3 addDependency:op2];

3 [op4 addDependency:op3];

注意:如果再加一句[op1 addDependency:op4]; 会造成循环依赖 

 如果所有UI的更新需要在主线程上进行那么将36行代码改为如下代码:

 [[NSOperationQueue mainQueue] addOperation:op4]; 

 加入以上代码最终结果为:

2014-06-17 20:11:41.629 NSOperation[12840:1303] 下载图片 <NSThread: 0x8d275c0>{name = (null), num = 2}
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略低,不过,大多数情况下这点负面影响可以忽略不计,操作队列是并发编程的首选工具


 

 

 

 

 

 

 

 

 

 

posted on 2014-06-17 22:19  键盘上的武者  阅读(242)  评论(0编辑  收藏  举报

导航