iOS多线程:NSOperation

一:简介
1.简介
NSOperation是一个抽象的基类,表示一个独立的计算单元,可以为子类提供有用且线程安全的建立状态,优先级,依赖和取消等操作。系统已经给我们封装了NSBlockOperation和NSInvocationOperation 这两个实体类。

2.执行和监听操作
NSOperation调用start方法即可开始执行操作,NSOperation对象默认按同步方式执行,也就是在start方法的那个线程中直接执行。
如果我们想在一个NSOperation执行完毕后做一些事情,就调用NSOperation的setCompletionBlock方法来设置想做的事情

3.NSOperation的子类
使用NSOperation子类的方式有3种

  • NSInvocationOperation
  • NSBlockOperation
  • 自定义子类继承NSOperation,实现内部相应的方法

二:具体使用

1.NSInvocationOperation
1.1 简介:
基于一个对象和selector来创建操作。如果你已经有现有的方法来执行需要的任务,就可以使用这个类
1.2 创建并执行操作

- (void)testNSInvocationOperation{
    //创建任务NSInvocationOperation 使用start开启,默认是同步执行
    NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downImage) object:nil];

    //监听任务结束
    [operation setCompletionBlock:^{
        NSLog(@"任务结束,当前线程==%@",[NSThread currentThread]);
    }];

    //开启任务,不写下面start,不会执行对应方法
    [operation start];
}

- (void)downImage{
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"下载图片1,当前线程==%@",[NSThread currentThread]);
}

打印结果:

2018-07-30 15:35:19.812267+0800 ThreadTest[40247:401579] 下载图片1,当前线程==<NSThread: 0x60c00006e740>{number = 1, name = main}
2018-07-30 15:35:19.812545+0800 ThreadTest[40247:401622] 任务结束,当前线程==<NSThread: 0x60800006f940>{number = 3, name = (null)}

2.NSBlockOperation
2.1 简介
能够并发的执行一个或多个block对象,所有相关的block都执行完成后,操作才算完成
2.2创建并执行操作

- (void)testNSBlockOperation{
    //创建任务NSInvocationOperation 使用start开启,默认是同步执行
    NSBlockOperation *blockOP = [NSBlockOperation blockOperationWithBlock:^{
        //任务
        [self downImage];
    }];

    //添加任务
    [blockOP addExecutionBlock:^{
        ZWWLog(@"任务2,当前线程==%@",[NSThread currentThread]);
    }];

    //添加任务
    [blockOP addExecutionBlock:^{
        ZWWLog(@"任务3,当前线程==%@",[NSThread currentThread]);
    }];

    //开启任务(这里还是同步执行),不写下面start,不会执行对应方法
    [blockOP start];
}

打印结果:

2018-07-30 15:40:21.767030+0800 ThreadTest[40740:406975] 任务3,当前线程==<NSThread: 0x604000262b80>{number = 4, name = (null)}
2018-07-30 15:40:21.767030+0800 ThreadTest[40740:406974] 任务2,当前线程==<NSThread: 0x60c00047a580>{number = 3, name = (null)}
2018-07-30 15:40:22.767559+0800 ThreadTest[40740:406915] 下载图片1,当前线程==<NSThread: 0x60c00007ab40>{number = 1, name = main}

3.NSOperationQueue
简介:
一个NSOperationQueue对象可以通过调用start方法来执行任务,默认是同步执行的。也可以将NSOperation添加到一个NSOperationQueue(操作队列)中去执行,而且是异步执行的。

//3.NSOperationQueue
- (void)testNSOperationQueue{


    //1.创建操作队列;全局并发队列,添加到队列里的任务都是异步执行的
    //NSOperationQueue相当于GCD中的 dispatch_get_global_queue
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];

    //2.创建任务
    NSInvocationOperation *invoOP = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downImage) object:nil];
    //    [queue addOperation:invoOP];

    NSBlockOperation *blockOP = [NSBlockOperation blockOperationWithBlock:^{
        //任务
        [self downImage];
    }];

    //添加任务到队列方法1
    //    [queue addOperation:blockOP];

     //3.添加多个任务到队列方法2
    [queue addOperations:@[invoOP,blockOP] waitUntilFinished:YES];

     //添加任务到队列方法2
//    [queue addOperationWithBlock:^{
//        NSLog(@"直接添加block任务,当前线程==%@",[NSThread currentThread]);
//    }];
//
//
//    dispatch_async(dispatch_get_global_queue(0, 0), ^{
//        ZWWLog(@"等同以上NSOperation操作");
//    });
}

打印结果:

2018-07-30 15:50:11.095684+0800 ThreadTest[41716:418465] 下载图片1,当前线程==<NSThread: 0x604000073440>{number = 3, name = (null)}
2018-07-30 15:50:11.095684+0800 ThreadTest[41716:418463] 下载图片1,当前线程==<NSThread: 0x60c00007ffc0>{number = 4, name = (null)}

4.最大并发数:maxConcurrentOperationCount

- (void)testOperationCount{
    //设置最大并发量,设置之后会两个两个一起来打印,不设置的话10个循环几乎同一时间并发打印
    //情况类似于 百度网盘同时勾选两个文件夹下载(可以把网速集中到某两个文件夹的下载上),不设置并发数的话,会多个线程共同并发执行,多个文件没有重要性区分
    self.opQueue.maxConcurrentOperationCount = 2;
    for (int i = 0; i<10; i++) {
        NSInvocationOperation *invoOP = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downImage) object:nil];
        [self.opQueue addOperation:invoOP];
    }
}

打印结果:

2018-07-30 16:00:52.356566+0800 ThreadTest[42570:428532] 下载图片1,当前线程==<NSThread: 0x60c00006c8c0>{number = 4, name = (null)}
2018-07-30 16:00:52.356573+0800 ThreadTest[42570:431306] 下载图片1,当前线程==<NSThread: 0x608000073700>{number = 6, name = (null)}
2018-07-30 16:00:53.360346+0800 ThreadTest[42570:428532] 下载图片1,当前线程==<NSThread: 0x60c00006c8c0>{number = 4, name = (null)}
2018-07-30 16:00:53.360392+0800 ThreadTest[42570:431313] 下载图片1,当前线程==<NSThread: 0x604000464100>{number = 7, name = (null)}
2018-07-30 16:00:54.362835+0800 ThreadTest[42570:431313] 下载图片1,当前线程==<NSThread: 0x604000464100>{number = 7, name = (null)}
2018-07-30 16:00:54.362835+0800 ThreadTest[42570:431306] 下载图片1,当前线程==<NSThread: 0x608000073700>{number = 6, name = (null)}
2018-07-30 16:00:55.366234+0800 ThreadTest[42570:431313] 下载图片1,当前线程==<NSThread: 0x604000464100>{number = 7, name = (null)}
2018-07-30 16:00:55.366255+0800 ThreadTest[42570:428532] 下载图片1,当前线程==<NSThread: 0x60c00006c8c0>{number = 4, name = (null)}
2018-07-30 16:00:56.369255+0800 ThreadTest[42570:431306] 下载图片1,当前线程==<NSThread: 0x608000073700>{number = 6, name = (null)}
2018-07-30 16:00:56.369255+0800 ThreadTest[42570:428532] 下载图片1,当前线程==<NSThread: 0x60c00006c8c0>{number = 4, name = (null)}

但是打印时,会两个两个一起来打印,不设置最大并发量的话10个循环几乎同一时间并发打印

5.依赖关系

- (void)testDependency{
    NSInvocationOperation *invoOP1 =  [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downImage) object:nil];

    NSBlockOperation *blockOP2 = [NSBlockOperation blockOperationWithBlock:^{
        [NSThread sleepForTimeInterval:10.0];
        NSLog(@"下载图片2,当前线程==%@",[NSThread currentThread]);
    }];
    NSBlockOperation *blockOP3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下载图片3,当前线程==%@",[NSThread currentThread]);
    }];

    NSBlockOperation *blockOP4 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"更新UI,当前线程==%@",[NSThread currentThread]);
    }];

    //添加依赖关系 invoOP1依赖blockOP2,blockOP2依赖blockOP3,所以先执行blockOP3
    [blockOP4 addDependency:invoOP1];
    [invoOP1 addDependency:blockOP2];
    [blockOP2 addDependency:blockOP3];
    [self.opQueue addOperations:@[invoOP1,blockOP2,blockOP3,blockOP4] waitUntilFinished:YES];
}

打印结果:

2018-07-30 15:58:22.415302+0800 ThreadTest[42570:428530] 下载图片3,当前线程==<NSThread: 0x604000466b00>{number = 3, name = (null)}
2018-07-30 15:58:32.419422+0800 ThreadTest[42570:428532] 下载图片2,当前线程==<NSThread: 0x60c00006c8c0>{number = 4, name = (null)}
2018-07-30 15:58:33.422490+0800 ThreadTest[42570:428532] 下载图片1,当前线程==<NSThread: 0x60c00006c8c0>{number = 4, name = (null)}
2018-07-30 15:58:33.422745+0800 ThreadTest[42570:428531] 更新UI,当前线程==<NSThread: 0x600000064140>{number = 5, name = (null)}

可以看到:
invoOP1依赖blockOP2,blockOP2依赖blockOP3,所以先执行blockOP3

demo链接,给个star鼓励下呗

猜你喜欢

转载自blog.csdn.net/wei371522/article/details/81286648