zoukankan      html  css  js  c++  java
  • 【iOS开发】多线程下NSOperation、NSBlockOperation、NSInvocationOperation、NSOperationQueue的使用

    http://blog.csdn.net/crycheng/article/details/21799611

    本篇文章主要介绍下多线程下NSOperation、NSBlockOperation、NSInvocationOperation、NSOperationQueue的使用,列举几个简单的例子。

    默认情况下,NSOperation并不具备封装操作的能力,必须使用它的子类,使用NSOperation子类的方式有3种:

    1> 自定义子类继承NSOperation,实现内部相应的方法

    2> NSBlockOperation

    3>NSInvocationOperation

    这讲先介绍如何用NSOperation封装一个操作,后面再结合NSOperationQueue来使用。

    1.首先介绍自定义NSOperation:

    NSOperation是没法直接使用的,它只是提供了一个工作的基本逻辑,具体实现还是需要你通过定义自己的NSOperation子类来获得。

    [objc] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. #import <Foundation/Foundation.h>  
    2.   
    3. @protocol NSDefineOprationDelegate <NSObject>  
    4.   
    5. - (void) handleDelegate;  
    6.   
    7. @end  
    8.   
    9. @interface NSDefineOpration : NSOperation  
    10.   
    11. @property (nonatomic, assign) id <NSDefineOprationDelegate> delegate;  
    12.   
    13. - (id)initWithDelegate:(id<NSDefineOprationDelegate>) delegate;  
    14. @end  

    实现文件里:

    [objc] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. #import "NSDefineOpration.h"  
    2.   
    3. @implementation NSDefineOpration  
    4.   
    5. - (id)initWithDelegate:(id<NSDefineOprationDelegate>) delegate  
    6. {  
    7.     if(self = [super init])  
    8.     {  
    9.         self.delegate = delegate;  
    10.     }  
    11.     return self;  
    12. }  
    13.   
    14. - (void)main  
    15. {  
    16.     @autoreleasepool {  
    17.         //do something  
    18.         sleep(15);  
    19.         NSLog(@"op1........handle......  on thread num :%@",[NSThread currentThread]);  
    20.           
    21.         if([self.delegate respondsToSelector:@selector(handleDelegate)])  
    22.         {  
    23.             [self.delegate performSelector:@selector(handleDelegate) withObject:nil];  
    24.         }  
    25.     }  
    26.       
    27. }  
    28.   
    29. @end  

    这里的sleep(15)主要用来做一些延时的操作,比如网络下载等。
    调用:

    [objc] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. - (void)oprationTest  
    2. {  
    3.     NSDefineOpration *op1 = [[NSDefineOpration alloc] initWithDelegate:self];  
    4.     op1.completionBlock = ^(){  
    5.         NSLog(@"op1........OK !!");  
    6.     };  
    7.     [op1 start];  
    8. }  


    执行结果:

    [objc] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. 2014-03-22 16:49:44.367 Operation[17353:60b] op1........handle......  on thread num :<NSThread: 0x1654ea20>{name = (null), num = 1}  
    2. 2014-03-22 16:49:49.373 Operation[17353:60b] op1.....callback.....  on thread num :<NSThread: 0x1654ea20>{name = (null), num = 1}  
    3. 2014-03-22 16:49:49.377 Operation[17353:1807] op1........OK !!  

    从执行结果可以看出,因为在实现的main函数里没有使用异步线程处理,导致直接阻塞了主线程1,所以使用这种方式一定注意main函数里操作时间过长导致主线程阻塞问题。耗时比较长的都放到其他线程里处理。

    2.接下来介绍NSBlockOperation

    第一种使用NSBlockOperation的方式:

     

    [objc] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. NSLog(@"block start");  
    2. NSBlockOperation *bop2 = [NSBlockOperation blockOperationWithBlock:^{  
    3.     sleep(15);  
    4.     NSLog(@"bop2.....handle..... on thread num%@",[NSThread currentThread]);  
    5. }];  
    6. [bop2 setCompletionBlock:^{  
    7.     NSLog(@"bop2........OK !!");  
    8. }];  
    9. [bop2 start];  

    * 第2行初始化了一个NSBlockOperation对象,它是用一个Block来封装需要执行的操作

    * 第9行调用了start方法,紧接着会马上执行Block中的内容

    看下执行结果:

    [objc] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. 2014-03-22 16:57:51.903 Operation[17374:60b] block start  
    2. 2014-03-22 16:58:06.908 Operation[17374:60b] bop2.....handle..... on thread num<NSThread: 0x16d83910>{name = (null), num = 1}  
    3. 2014-03-22 16:58:06.912 Operation[17374:360b] bop2........OK !!  

    * 这里还是在当前线程同步执行操作,并没有异步执行,阻塞主线程。

    第二种使用NSBlockOperation的方式:

    [objc] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. - (void)blockOprationTest  
    2. {  
    3.     NSLog(@"block start");  
    4.     NSBlockOperation * op2 = [[NSBlockOperation alloc] init];  
    5.     [op2 addExecutionBlock:^{  
    6.         sleep(10);  
    7.         NSLog(@"op2.....handle..... on 10 hread num%@",[NSThread currentThread]);  
    8.     }];  
    9.       
    10.     [op2 addExecutionBlock:^{  
    11.         sleep(6);  
    12.         NSLog(@"op2.....handle..... on 6 thread num%@",[NSThread currentThread]);  
    13.     }];  
    14.       
    15.     [op2 addExecutionBlock:^{  
    16.         sleep(4);  
    17.         NSLog(@"op2.....handle..... on 4 thread num%@",[NSThread currentThread]);  
    18.     }];  
    19.       
    20.     [op2 addExecutionBlock:^{  
    21.         sleep(8);  
    22.         NSLog(@"op2.....handle..... on 8 thread num%@",[NSThread currentThread]);  
    23.     }];  
    24.       
    25.     [op2 addExecutionBlock:^{  
    26.         sleep(1);  
    27.         NSLog(@"op2.....handle..... on 1 thread num%@",[NSThread currentThread]);  
    28.     }];  
    29.     [op2 setCompletionBlock:^{  
    30.         NSLog(@"op2........OK !!");  
    31.     }];  
    32.     [op2 start];  
    33.       
    34.     //bop2  
    35.     NSBlockOperation *bop2 = [NSBlockOperation blockOperationWithBlock:^{  
    36.         sleep(15);  
    37.         NSLog(@"bop2.....handle..... on thread num%@",[NSThread currentThread]);  
    38.     }];  
    39.     [bop2 setCompletionBlock:^{  
    40.         NSLog(@"bop2........OK !!");  
    41.     }];  
    42.     [bop2 start];  
    43. }  

    执行结果:

    [objc] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. 2014-03-22 17:02:56.027 Operation[17396:60b] block start  
    2. 2014-03-22 17:03:02.032 Operation[17396:1803] op2.....handle..... on thread num<NSThread: 0x17573400>{name = (null), num = 2}  
    3. 2014-03-22 17:03:06.032 Operation[17396:60b] op2.....handle..... on 10 hread num<NSThread: 0x1755eca0>{name = (null), num = 1}  
    4. 2014-03-22 17:03:06.035 Operation[17396:1803] op2.....handle..... on thread num<NSThread: 0x17573400>{name = (null), num = 2}  
    5. 2014-03-22 17:03:07.038 Operation[17396:1803] op2.....handle..... on thread num<NSThread: 0x17573400>{name = (null), num = 2}  
    6. 2014-03-22 17:03:14.035 Operation[17396:60b] op2.....handle..... on thread num<NSThread: 0x1755eca0>{name = (null), num = 1}  
    7. 2014-03-22 17:03:14.037 Operation[17396:1807] op2........OK !!  
    8. 2014-03-22 17:03:29.038 Operation[17396:60b] bop2.....handle..... on thread num<NSThread: 0x1755eca0>{name = (null), num = 1}  
    9. 2014-03-22 17:03:29.041 Operation[17396:180b] bop2........OK !!  


    分析下结果:

    首先看到了有1和2两个线程,线程2在56秒的时候开始执行6秒的操作,接下来执行4,1秒结束时间为07秒。线程1在56的时候开始执行10秒的操作,接下来执行8秒,结束时间为14秒。最后执行Bop2的15秒操作至29秒。时间看起来没有问题。为什么会启用2个线程而不是3个或者更多?

    3.接下来介绍NSInvocationOperation

    [objc] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. - (void)invocationOperation  
    2. {  
    3.     NSInvocationOperation * op3 = [[NSInvocationOperation alloc] initWithTarget:(id)self selector:@selector(handleInvoOpDelegate) object:nil];  
    4.     [op3 setCompletionBlock:^{  
    5.         NSLog(@"op3........OK !!");  
    6.     }];  
    7.     [op3 start];  
    8. }  


    selector函数:

    [objc] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. - (void)handleInvoOpD  
    2. {  
    3.     sleep(5);  
    4.     NSLog(@"op3.....handle.....  on thread num :%@",[NSThread currentThread]);  
    5. }  


    执行结果:

     

    [objc] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. 2014-03-22 17:11:13.050 Operation[17421:60b] op3.....handle.....  on thread num :<NSThread: 0x1653ac30>{name = (null), num = 1}  
    2. 2014-03-22 17:11:13.055 Operation[17421:1803] op3........OK !!  


    NSInvocationOperation比较简单,就是继承了NSOperation,区别就是它是基于一个对象和selector来创建操作,可以直接使用而不需继承来实现自己的操作处理。

    4.最后介绍下NSOperationQueue

    把NSOperation子类的对象放入NSOperationQueue队列中,该队列就会启动并开始处理它。队列里可以加入很多个NSOperation, 可以把NSOperationQueue看作一个线程池,可往线程池中添加操作(NSOperation)到队列中。线程池中的线程可看作消费者,从队列中取走操作,并执行它。

    实现demo:

    [objc] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. - (void)handleOpqueue  
    2. {  
    3.     NSOperationQueue *qu = [[NSOperationQueue alloc] init];  
    4.       
    5.     NSBlockOperation * bkOp1 = [NSBlockOperation blockOperationWithBlock:^{  
    6.         sleep(10);  
    7.         NSLog(@"bkOp1.....handle.....on thread num%@",[NSThread currentThread]);  
    8.     }];  
    9.     [bkOp1 setCompletionBlock:^{  
    10.         NSLog(@"bkOp1........OK !!");  
    11.     }];  
    12.       
    13.       
    14.     NSBlockOperation * bkOp2 = [NSBlockOperation blockOperationWithBlock:^{  
    15.         sleep(2);  
    16.         NSLog(@"bkOp2.....handle.....on thread num%@",[NSThread currentThread]);  
    17.     }];  
    18.     [bkOp2 setCompletionBlock:^{  
    19.         NSLog(@"bkOp2........OK !!");  
    20.     }];  
    21.       
    22.     NSBlockOperation * bkOp3 = [NSBlockOperation blockOperationWithBlock:^{  
    23.         sleep(1);  
    24.         NSLog(@"bkOp3.....handle.....on thread num%@",[NSThread currentThread]);  
    25.     }];  
    26.     [bkOp3 setCompletionBlock:^{  
    27.         NSLog(@"bkOp3........OK !!");  
    28.     }];  
    29.       
    30.     NSBlockOperation * bkOp4 = [NSBlockOperation blockOperationWithBlock:^{  
    31.         sleep(10);  
    32.         NSLog(@"bkOp4.....handle.....on thread num%@",[NSThread currentThread]);  
    33.     }];  
    34.     [bkOp4 setCompletionBlock:^{  
    35.         NSLog(@"bkOp4........OK !!");  
    36.     }];  
    37.       
    38.     NSBlockOperation * bkOp5 = [NSBlockOperation blockOperationWithBlock:^{  
    39.         sleep(5);  
    40.         NSLog(@"bkOp5.....handle.....on thread num%@",[NSThread currentThread]);  
    41.     }];  
    42.     [bkOp5 setQueuePriority:NSOperationQueuePriorityHigh];  
    43.     [bkOp5 setCompletionBlock:^{  
    44.         NSLog(@"bkOp5........OK !!");  
    45.     }];  
    46.       
    47.     NSInvocationOperation *invoOp6 = [[NSInvocationOperation alloc] initWithTarget:(id)self selector:@selector(handleInvoOp) object:nil];  
    48.     [invoOp6 setCompletionBlock:^{  
    49.         NSLog(@"invoOp6........OK !!");  
    50.     }];  
    51.     [invoOp6 setQueuePriority:NSOperationQueuePriorityHigh];  
    52.       
    53.     [qu setMaxConcurrentOperationCount:2];  
    54.     [qu addOperation:bkOp3];  
    55.     [qu addOperation:bkOp2];  
    56.     [qu addOperation:bkOp1];  
    57.     [qu addOperation:bkOp4];  
    58.     [qu addOperation:bkOp5];  
    59.     [qu addOperation:invoOp6];  
    60. }  


    先看下执行结果:

    [objc] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. 2014-03-22 17:18:36.634 Operation[17439:1803] bkOp3.....handle.....on thread num<NSThread: 0x1754c450>{name = (null), num = 2}  
    2. 2014-03-22 17:18:36.638 Operation[17439:1803] bkOp3........OK !!  
    3. 2014-03-22 17:18:37.635 Operation[17439:3607] bkOp2.....handle.....on thread num<NSThread: 0x1765a320>{name = (null), num = 3}  
    4. 2014-03-22 17:18:37.637 Operation[17439:3607] bkOp2........OK !!  
    5. 2014-03-22 17:18:41.640 Operation[17439:3d07] bkOp5.....handle.....on thread num<NSThread: 0x17562d10>{name = (null), num = 4}  
    6. 2014-03-22 17:18:41.642 Operation[17439:3d07] bkOp5........OK !!  
    7. 2014-03-22 17:18:42.639 Operation[17439:1803] invoOp6.....handle.....  on thread num :<NSThread: 0x1754c450>{name = (null), num = 2}  
    8. 2014-03-22 17:18:42.643 Operation[17439:1803] invoOp6........OK !!  
    9. 2014-03-22 17:18:51.644 Operation[17439:3607] bkOp1.....handle.....on thread num<NSThread: 0x1765a320>{name = (null), num = 3}  
    10. 2014-03-22 17:18:51.646 Operation[17439:3607] bkOp1........OK !!  
    11. 2014-03-22 17:18:52.645 Operation[17439:3d07] bkOp4.....handle.....on thread num<NSThread: 0x17562d10>{name = (null), num = 4}  
    12. 2014-03-22 17:18:52.647 Operation[17439:3d07] bkOp4........OK !!  


    从结果可以看出,NSOperationQueue在2,3,4这3个线程里去处理NSOperation,而不包括主线程1。此外,在设置了bkop5以及invOp6的优先级为高时,他们会优先执行,当然这个优先时相对,是相对正在排队的,不包括已经正在执行的。

    总结:NSOperation、NSBlockOperation、NSInvocationOperation、NSOperationQueue都比较简单,NSOperation、NSBlockOperation、NSInvocationOperation单个都是表示一种操作,而NSOperationQueue是一个可以包含多个NSOperation的队列,可以自己在多个线程处理,只要加入队列之后,我们就不用去操作,直到Callback或者完成。

    参考资料:

    http://blog.csdn.net/totogo2010/article/details/8013316

    http://www.cnblogs.com/mjios/archive/2013/04/19/3029765.html

  • 相关阅读:
    pip不是内部或外部命令也不是可运行的程序或批处理文件的问题
    动态规划 leetcode 343,279,91 & 639. Decode Ways,62,63,198
    动态规划 70.climbing Stairs ,120,64
    (双指针+链表) leetcode 19. Remove Nth Node from End of List,61. Rotate List,143. Reorder List,234. Palindrome Linked List
    建立链表的虚拟头结点 203 Remove Linked List Element,82,147,148,237
    链表 206 Reverse Linked List, 92,86, 328, 2, 445
    (数组,哈希表) 219.Contains Duplicate(2),217 Contain Duplicate, 220(3)
    重装系统
    java常用IO
    端口
  • 原文地址:https://www.cnblogs.com/paranoia/p/5737927.html
Copyright © 2011-2022 走看看