ios NSOperation 和NSOperationQueue

ios 中gcd功能还是很强大的,但是gcd都是c函数,使用的时候可能总是感觉不是很方便。那么有没有oc实现的呢,当然有了,就是NSOperation和NSOperationQueue,其实它们就是对gdc的包装。下面我就来看一下他们的使用

NSOperation是一个抽象类,不能用来封装操作。只能用的他的子类来封装。我们有三种方式来封装分别是:

  1. 使用子类 NSInvocationOperation
  2. 使用子类 NSBlockOperation
  3. 自定义继承自 NSOperation 的子类,通过实现内部相应的方法来封装操作。

下面我们主要说一下前两种情况。

       NSInvocationOperation

-(void)invocationOperationTest{

    *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task1:) object:@"mainQueue"];

    [op1 start];

    NSInvocationOperation *op2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(task1:) object:@"otherQueue"];

    NSOperationQueue * opQueue = [[NSOperationQueue alloc]init];

    [opQueue addOperation:op2];

    

}


-(void)task1:(NSString*)param{

    for(int i=0; i<2;i++){

        [NSThread sleepForTimeInterval:2];

        NSLog(@"param:%@,thread:%@",param,[NSThread currentThread]);

    }

}

执行后的log是这样的:

param:mainQueue,thread:{number = 1, name = main}

2018-05-18 14:00:34.867450+0800 ocLearner[64622:3297731] param:mainQueue,thread:{number = 1, name = main}

2018-05-18 14:00:36.871585+0800 ocLearner[64622:3298021] param:otherQueue,thread:{number = 3, name = (null)}

2018-05-18 14:00:38.872211+0800 ocLearner[64622:3298021] param:otherQueue,thread:{number = 3, name = (null)}

可以看到,如果不把NSInvocationOperation添加到队列中,默认是使用主队列的。因此操作也将在主线程中运行。如果添加到自定义的队列中,将在新开启的线程中运行。

那么,NSBlockOperation是什么情况呢,看代码:

//使用主线程

    NSLog(@"mian thread:%@",[NSThread currentThread]);

    NSBlockOperation *op1 =[NSBlockOperation blockOperationWithBlock:^{

        for(int i=0;i<2;i++){

            [NSThread sleepForTimeInterval:2];

            NSLog(@"01---%@",[NSThread currentThread]);

        }

    }];

    [op1 start];

    //使用addExecutionBlock添加多个操作后有可能不在主线程执行,具体哪个线程由系统决定

    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{

        for(int i=0;i<2;i++){

            [NSThread sleepForTimeInterval:2];

            NSLog(@"1---%@",[NSThread currentThread]);

        }

    }];

    

    [op2 addExecutionBlock:^{

        for (int i = 0; i < 2; i++) {

            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作

            NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程

        }

    }];

    

    [op2 addExecutionBlock:^{

        for (int i = 0; i < 2; i++) {

            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作

            NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程

        }

    }];

    [op2 addExecutionBlock:^{

        for (int i = 0; i < 2; i++) {

            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作

            NSLog(@"3---%@", [NSThread currentThread]); // 打印当前线程

        }

    }];

    [op2 addExecutionBlock:^{

        for (int i = 0; i < 2; i++) {

            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作

            NSLog(@"4---%@", [NSThread currentThread]); // 打印当前线程

        }

    }];

    [op2 addExecutionBlock:^{

        for (int i = 0; i < 2; i++) {

            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作

            NSLog(@"5---%@", [NSThread currentThread]); // 打印当前线程

        }

    }];

    [op2 addExecutionBlock:^{

        for (int i = 0; i < 2; i++) {

            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作

            NSLog(@"6---%@", [NSThread currentThread]); // 打印当前线程

        }

    }];

    [op2 addExecutionBlock:^{

        for (int i = 0; i < 2; i++) {

            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作

            NSLog(@"7---%@", [NSThread currentThread]); // 打印当前线程

        }

    }];

    [op2 start];

    

    //使用自定义的OperationQueue,会启用新线程,而且可以不用定义NSBlockOperation,直接在OpertionQueue中添加就可以

    NSOperationQueue * opQueue = [[NSOperationQueue alloc]init];

    [opQueue addOperationWithBlock:^{

        for (int i = 0; i < 2; i++) {

            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作

            NSLog(@"001---%@", [NSThread currentThread]); // 打印当前线程

        }

    }];

    

    [opQueue addOperationWithBlock:^{

        for (int i = 0; i < 2; i++) {

            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作

            NSLog(@"002---%@", [NSThread currentThread]); // 打印当前线程

        }

    }];

    

    [opQueue addOperationWithBlock:^{

        for (int i = 0; i < 2; i++) {

            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作

            NSLog(@"003---%@", [NSThread currentThread]); // 打印当前线程

        }

    }];

    

    [opQueue addOperationWithBlock:^{

        for (int i = 0; i < 2; i++) {

            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作

            NSLog(@"004---%@", [NSThread currentThread]); // 打印当前线程

        }

    }];

    

    [opQueue addOperationWithBlock:^{

        for (int i = 0; i < 2; i++){

            [NSThread sleepForTimeInterval:2]; // 模拟耗时操作

            NSLog(@"005---%@", [NSThread currentThread]); // 打印当前线程

        }

    }];

运行后的Log如图:

2018-05-18 14:06:10.910712+0800 ocLearner[64762:3304313] 01---{number = 1, name = main}

2018-05-18 14:06:12.912342+0800 ocLearner[64762:3304313] 01---{number = 1, name = main}

2018-05-18 14:06:14.913720+0800 ocLearner[64762:3304313] 2---{number = 1, name = main}

2018-05-18 14:06:14.913752+0800 ocLearner[64762:3304688] 1---{number = 3, name = (null)}

2018-05-18 14:06:14.913838+0800 ocLearner[64762:3305021] 2---{number = 4, name = (null)}

2018-05-18 14:06:14.913841+0800 ocLearner[64762:3305022] 3---{number = 5, name = (null)}

2018-05-18 14:06:16.914733+0800 ocLearner[64762:3305021] 2---{number = 4, name = (null)}

2018-05-18 14:06:16.914733+0800 ocLearner[64762:3304688] 1---{number = 3, name = (null)}

2018-05-18 14:06:16.914775+0800 ocLearner[64762:3304313] 2---{number = 1, name = main}

2018-05-18 14:06:16.923115+0800 ocLearner[64762:3305022] 3---{number = 5, name = (null)}

2018-05-18 14:06:18.916370+0800 ocLearner[64762:3305021] 4---{number = 4, name = (null)}

2018-05-18 14:06:18.916559+0800 ocLearner[64762:3304688] 5---{number = 3, name = (null)}

2018-05-18 14:06:18.916611+0800 ocLearner[64762:3304313] 6---{number = 1, name = main}

2018-05-18 14:06:18.923713+0800 ocLearner[64762:3305022] 7---{number = 5, name = (null)}

2018-05-18 14:06:20.918033+0800 ocLearner[64762:3304313] 6---{number = 1, name = main}

2018-05-18 14:06:20.918031+0800 ocLearner[64762:3305021] 4---{number = 4, name = (null)}

2018-05-18 14:06:20.918033+0800 ocLearner[64762:3304688] 5---{number = 3, name = (null)}

2018-05-18 14:06:20.925326+0800 ocLearner[64762:3305022] 7---{number = 5, name = (null)}

2018-05-18 14:06:22.930418+0800 ocLearner[64762:3305021] 003---{number = 4, name = (null)}

2018-05-18 14:06:22.930418+0800 ocLearner[64762:3305022] 001---{number = 5, name = (null)}

2018-05-18 14:06:22.930454+0800 ocLearner[64762:3304688] 002---{number = 3, name = (null)}

2018-05-18 14:06:22.930576+0800 ocLearner[64762:3305295] 005---{number = 6, name = (null)}

2018-05-18 14:06:22.930611+0800 ocLearner[64762:3305294] 004---{number = 7, name = (null)}

2018-05-18 14:06:24.933813+0800 ocLearner[64762:3305022] 001---{number = 5, name = (null)}

2018-05-18 14:06:24.933871+0800 ocLearner[64762:3305295] 005---{number = 6, name = (null)}

2018-05-18 14:06:24.933879+0800 ocLearner[64762:3305021] 003---{number = 4, name = (null)}

2018-05-18 14:06:24.933811+0800 ocLearner[64762:3304688] 002---{number = 3, name = (null)}

2018-05-18 14:06:24.933930+0800 ocLearner[64762:3305294] 004---{number = 7, name = (null)}


可以看到,如果是单个操作,且不添加到自定义队列中,操作将在主线程中运行。如果是多个操作,将由系统决定在哪个线程中运行(这些线程包括主线程),如果是添加到自定义队列,则全部在非主线程中运行。

另外,NSOperation最大的特点是可以设置操作依赖,也就是如果操作A依赖操作B,那么A必须等B完成后才能执行。

用这个函数可以实现:

-(void)addDependency:(NSOperation *)op;

下面来来看一下代码,很简单:

NSOperationQueue *queue =[[NSOperationQueue alloc]init];

    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{

        for(int i=0;i<2;i++){

            [NSThread sleepForTimeInterval:2];

            NSLog(@"1---%@",[NSThread currentThread]);

        }

    }];

    

    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{

        for(int i=0;i<2;i++){

            [NSThread sleepForTimeInterval:2];

            NSLog(@"2----%@",[NSThread currentThread]);

        }

    }];

    [op2 addDependency:op1];//让op2 依赖于 op1

    

    [queue addOperation:op1];

    [queue addOperation:op2];

这个代码无论运行多少次,op1都是在op2之前执行。

好了,先写这么多吧,以后有需要再添加吧。

你可能感兴趣的:(IOS)