码迷,mamicode.com
首页 > 编程语言 > 详细

多线程工具之NSOperationQueue

时间:2015-09-19 16:31:20      阅读:177      评论:0      收藏:0      [点我收藏+]

标签:

优点:
        使用NSOperationQueue方式进行多线程编程,不能够像NSThread一样直接管理线程(是看不见线程的),也不需要管理,但是可以间接的干预线程。
 
1.NSOperation
           是一个抽象类,用来封装单任务的代码和数据
抽象类,所以不能直接使用该类,而是创建子类或者一些系统定义的子类 (NSInvocationOperation 或者 NSBlockOperation)来完成实际的任务。
 
2.NSOperation子类的创建
 
//子类CNOperation的创建继承NSOperation
    CNOperation* op = [[CNOperation alloc]init];
//NSOperation默认并不会执行,必须调用start方法
    [op start];
 
 
#import "CNOperation.h"

@implementation CNOperation
- (void)main{
 
    NSLog(@"do something");
}
@end
 
3.系统自带的NSOperation子类
(NSInvocationOperation 或者 NSBlockOperation)
 
1.创建NSInvocationOperation
    NSInvocationOperation* iop = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(invoAction) object:nil];
    [iop start];
   
 
 
2.创建NSBlockOperation
    1.系统block    
    NSBlockOperation* bop = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"do other something");
    }];
    [bop start];
 
    2.自定义block
//在CNOperation类中自己写block也可以
@property(copy)void(^block)(void);
 
//在CNOperation类中的main方法中调用block
- (void)main{
    //调用block
    if (_block) {
        _block();
    }
 
 CNOperation* cn = [[CNOperation alloc]init];
    //block实现
    [cn setBlock:^{
        NSLog(@"do something");
        //死循环
       // while(true){
//
       // }
    }];
    [cn start];
         // NSLog(@“因为有死循环,所以该语句永远不会被打印出来”);
小结:
       NSOperation默认并不会执行,必须调用start方法,执行时默认在当前线程中执行,即 默认同步执行。
 
什么实同步执行呢?
        就是block执行不完,start就不会执行
怎样调用的呢?
        比如在上面的代码中,默认程序先走到start,start又调用的main,main又调用的block ,层层调用,后调用的先执行,所以block先执行start后执行,先打印do something 
技术分享
4.NSOperationQueue
 
一个NSOperationQueue对象并非一个线程,而是线程管理器,可以帮我们自动创建新的线 程。
取决于队列的最大并行数。NSOperation对象添加到队列中,默认就成为了异步执行(非 当前线程)。
 
1.解释同步执行和异步执行,演示Queue是怎样实现的异步执行
CNOperation* cn = [[CNOperation alloc]init];
    //block实现
    [cn setBlock:^{
        NSLog(@"do something");
        //死循环
        while (true) {
           
        }
    }];
    //同步执行(在当前线程执行op任务),该start永远不会被执行,因为block中有死循环,block执行不完,start不会被执行
//    [cn start];
    //异步执行(在其他线程执行op任务), 该start不会被执行,后面的代码会被打印,因为异步执行是不管block执不执行完,start都会执行
         //异步执行只需要将start方法放到新的线程中调用,该performSelectorInBackground是隐式创建的线程,我们都没有办法管理他,所以我们用queue来创建新的线程,这就是新学的内容
    [cn performSelectorInBackground:@selector(start) withObject:nil];
    NSLog(@"aaa");
5.创建NSOperationQueue
 
1.创建NSOperationQueue
 
  //创建线程管理器
    NSOperationQueue* opQ = [[NSOperationQueue alloc]init];
   
 
2.添加单个operation到queue中
 
NSBlockOperation* bop1 = [NSBlockOperation blockOperationWithBlock:^{
       
        NSLog(@"bop1......");
        NSLog(@"bop1:%@",[NSThread currentThread]);
//        usleep(1000000);
 
    }];
    //添加到queue后,不需要手动start,会自动开始执行
//    [bop1 start];
   
   
    NSBlockOperation* bop2 = [NSBlockOperation blockOperationWithBlock:^{
       
        NSLog(@"bop2.......");
        NSLog(@"bop2:%@",[NSThread currentThread]);
//        usleep(1000000);


    }];
//    [bop2 start];
   
    //添加到Queue中的NSOperation会自动执行,执行的时间取决于两个因素一个是依赖。一个是优先级
//    [opQ addOperation:bop1];
//    [opQ addOperation:bop2];
3.可以同时添加多个OperationQueue
 
//可以同时添加多个Operation到Queue中
    //waitUntilFinished设置为NO就是不用等待queue全部执行完就可以执行后面的语句--ok---
    //waitUntilFinished设置为YES就是等待queue全部执行完后才可以执行后面的语句
    [opQ addOperations:@[bop1,bop2] waitUntilFinished:YES];
    NSLog(@"-----OK-----");
 
 
4.队列的最大并发数
 
    //设置队列的最大并发数
    //最大并行数为1时,所有的op都会串行,并不代表只有一个线程1-1-2-2
    opQ.maxConcurrentOperationCount = 1;
技术分享
/ / 若不设置最大并发书打印的operation可能会交替出现2-1-2-1
技术分享
5. 可以隐式的添加一个OperationQueue
 
意思是不需要自己创建一个operation,而是让queue自己创建
[opQ addOperationWithBlock:^{
        NSLog(@"可以隐式的添加一个Operation到Queue中");
        NSLog(@"keyi:%@",[NSThread currentThread]);
 
//        usleep(1000000);
    }];
6.添加NSOperation的依赖对象
 
注意:
NSOperation添加到queue之后,绝对不要再修改NSOperation对象的状态,因为此时的operation可能会在任何时候运行,因此只能查看NSOperation对象的状态,比如是否正在运行,等待运行,已经完成等。
 
6.1添加依赖
添加依赖成功的前提是必须将operation添加到queue中,因为自动执行才有可能产生依赖关系
 
 
 NSOperationQueue *queue = [[NSOperationQueue alloc] init];
   
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^()
                                    {
                                        NSLog(@"执?行第1次操作,1:%@", [NSThread currentThread]);
                                    }];
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^()
                                    {
                                        NSLog(@"执?行第2次操作,2:%@", [NSThread currentThread]);
                                    }];
    NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^()
                                    {
                                        NSLog(@"执?行第3次操作,3:%@", [NSThread currentThread]);
                                    }];
    
    //添加依赖
    //依赖关系会影响到NSOperation对象在queue中的执行顺序
    //添加依赖成功的前提,必须将Operation添加到Queue中
         / / 添加依赖后默认会在同一个线程中执行,不完全对
    [operation1 addDependency:operation2];
技术分享
    [operation1 addDependency:operation3];
   
    //添加多个依赖后,上边的话就不对,而应该改operation1会在最后执行的依赖operation执行的线程中执行 
    //意思是op2依赖于op1所以op2先执行,而op3依赖于op1所以op3先执行,那么op2和op3谁先执行呢?op3和op2不一定谁先执行,op1会在依赖的最后一个线程中执行,因为当前打印中op2最后执行,所以op1和op2是在同一个线程
技术分享
 
   //设置优先级
    //首先根据依赖关系,确定前后执行顺序,其次在满足依赖关系的前提下,再根据优先级排序。
    operation2.qualityOfService = NSQualityOfServiceUserInteractive;
    operation3.qualityOfService = NSQualityOfServiceBackground;
//
    
//    //注意:不能创建环形依赖,比如A依赖B,B依赖A,这是错误的,
//    [operation2 addDependency:operation1];
   //op2执行不完op1不能执行,op1执行不完op2不能执行
  //添加到queue之前添加依赖
    //打印出来的执行顺序不确定
    //添加到queue中的operation不应该再去修改属性
    [queue addOperation:operation1];
    [queue addOperation:operation2];
    [queue addOperation:operation3];
7. NSOperationQueue的取消,等待, 暂停和继续queue
 
NSOperationQueue* queue = [[NSOperationQueue alloc]init];
   
    NSBlockOperation* op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"block opreation1");
        NSLog(@"1:%@",[NSThread currentThread]);
    }];
   
    NSBlockOperation* op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"block opreation2");
        NSLog(@"2:%@",[NSThread currentThread]);
       
        //取消op1 必须在op1执行前取消,否者无效
//        [op1 cancel];
     
        //暂停,,不是operation暂停和继续,任务开始后无法暂停取消,而是queue暂停和取消,暂停queue,不会暂停当前正在执行的operation,而是一直执行完,暂停只是会停止开启新的在等待的operation
//        [queue setSuspended:YES];
        //因为operation2正在执行,所以不会被暂停,而operation1被暂停
技术分享
       
    }];
 
   
    //没添加依赖前,op开始执行后无法取消,仍然把op1和op2都执行出来
技术分享
         / /但是添加依赖后就不一样了,添加依赖后op2先执行,此时op1还没有执行,这是就可以取消op1了
    [op1 addDependency:op2];
技术分享
   
    [queue addOperation:op1];
    [queue addOperation:op2];
    
    //取消queue中的所有的操作
//     [queue cancelAllOperations];
   
    //等待卡死当前线程
    //等待op2执行完毕后,再执行
//    [op2 waitUntilFinished];
技术分享
    //等待queue所有操作执行完毕后执行
    [queue waitUntilAllOperationsAreFinished];
    NSLog(@"..........");
   
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //延时3秒后继续queue
        [queue setSuspended:NO];
    });

多线程工具之NSOperationQueue

标签:

原文地址:http://www.cnblogs.com/gaominmin/p/4821511.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!