爱博体育app手机版iOS三多线程开拓之NSOperation

1. NSOperation简介

NSOperation
是苹果提需要大家的一套四线程技术方案。实际上NSOperation是依照GCD越来越高级中学一年级层的包装,可是比GCD更简明易用、代码可读性也越来越高。

NSOperation须求合作NSOperationQueue来完结十六线程。因为在暗中同意情形下,NSOperation单独选择时系统同步推行操作,并未开拓新线程的技能,独有NSOperationQueue技巧实现异步施行。

NSOperation是依照GCD的,那么使用起来也和GCD大概,当中,NSOperation也就是GCD中的职务,而NSOperationQueue则也正是GCD中的队列。NSOperation达成四线程的使用手续分为三步:

  • 创制任务:先将索要实施的操作封装到三个NSOperation对象中;
  • 成立队列:创制NSOperationQueue对象;
  • 将职分出席到行列中:然后将NSOperation对象增多到NSOperationQueue中。

从此,系统就能活动将NSOperationQueue中的NSOperation抽取来,在光山县城中执行操作。

– – – – – – – – –
上面我们来学习下NSOperation和NSOperationQueue的着力使用 – – – – – – 

一、什么是NSOperation?

     
NSOperation是苹果提供的一套十二线程解决方案。实际上NSOperation是依赖GCD更加高级中学一年级层的包装,不过比GCD越来越面向对象、代码可读性更加高、可控性越来越强,异常的棒的是走入了操作依赖。

      暗许意况下,NSOperation单独行使时只可以同步实行操作,并从未开采新线程的技艺,只有合作NSOperationQueue技术达成异步实践。讲到这里,大家简单开掘GCD和NSOperation达成的必定要经过的道路很像,其实那更疑似废话,NSOperation本身就是基于GCD的卷入,NSOperation也正是GCD中的职务,而NSOperationQueue则也正是GCD中的队列,前面《iOS多线程开采之GCD(上篇)》中早就演讲过GCD的本色:开辟者要做的只是概念想进行的天职并扩大到合适的Dispatch
Queue中。那样大家也可说NSOperation的原形就是:定义想实行的职务(NSOperation)并扩张到相当的NSOperationQueue中。

 

2. NSOperation的着力使用

二、NSOperation使用

     1、创设职责

   
 NSOperation是三个抽象的基类,表示叁个单身的测算单元,可感觉子类提供有用且线程安全的创设意况,优先级,注重和撤除等操作。但它不能直接用来封装职分,只可以通过它的子类来封装,一般的我们能够运用:NSBlockOperation、NSInvocationOperation大概定义承接自NSOperation的子类,通过落实内部相应的措施来封装职分。

   (1)NSInvocationOperation

- (void)invocationOperation{

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

    // 创建NSInvocationOperation对象
    NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(testRun) object:nil];

    // 调用start方法开始执行操作
    [op start];

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

- (void)testRun{
    NSLog(@"invocationOperation -- %@", [NSThread currentThread]);
}

    实践结果:

2017-07-14 13:43:59.327 beck.wang[10248:1471363] start - <NSThread: 0x6100000614c0>{number = 1, name = main}
2017-07-14 13:43:59.328 beck.wang[10248:1471363] invocationOperation -- <NSThread: 0x6100000614c0>{number = 1, name = main}
2017-07-14 13:43:59.328 beck.wang[10248:1471363] end - <NSThread: 0x6100000614c0>{number = 1, name = main}

    分析:单独使用NSInvocationOperation的境况下,NSInvocationOperation在主线程同步实践操作,并从未开启新线程。

  (2)NSBlockOperation

- (void)blockOperation{

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

    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{

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

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

    [op start];
}

    打字与印刷结果:

2017-07-14 13:49:25.436 beck.wang[10304:1476355] start - <NSThread: 0x6100000653c0>{number = 1, name = main}
2017-07-14 13:49:25.436 beck.wang[10304:1476355] end - <NSThread: 0x6100000653c0>{number = 1, name = main}
2017-07-14 13:49:25.436 beck.wang[10304:1476355] blockOperation--<NSThread: 0x6100000653c0>{number = 1, name = main}

    深入分析:单独行使NSBlockOperation的气象下,NSBlockOperation也是在主线程实践操作,未有开启新线程。

   
值得注意的是:NSBlockOperation还提供了三个方法addExecutionBlock:,通过addExecutionBlock:就能够为NSBlockOperation增加额外的操作,那么些额外的操作就能在另外线程并发实行。

- (void)blockOperation{

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

    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{

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

    // 添加额外任务(在子线程执行)
    [op addExecutionBlock:^{
        NSLog(@"addTask1---%@", [NSThread currentThread]);
    }];
    [op addExecutionBlock:^{
        NSLog(@"addTask2---%@", [NSThread currentThread]);
    }];
    [op addExecutionBlock:^{
        NSLog(@"addTask3---%@", [NSThread currentThread]);
    }];

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

    [op start];
}

     打字与印刷结果:

2017-07-14 13:57:02.009 beck.wang[10351:1482603] start - <NSThread: 0x60000007cdc0>{number = 1, name = main}
2017-07-14 13:57:02.009 beck.wang[10351:1482603] end - <NSThread: 0x60000007cdc0>{number = 1, name = main}
2017-07-14 13:57:02.010 beck.wang[10351:1482603] blockOperation--<NSThread: 0x60000007cdc0>{number = 1, name = main}
2017-07-14 13:57:02.010 beck.wang[10351:1482642] addTask1---<NSThread: 0x618000260e00>{number = 3, name = (null)}
2017-07-14 13:57:02.010 beck.wang[10351:1482645] addTask3---<NSThread: 0x600000263200>{number = 5, name = (null)}
2017-07-14 13:57:02.010 beck.wang[10351:1482643] addTask2---<NSThread: 0x610000264600>{number = 4, name = (null)}

    解析:blockOperationWithBlock义务在主线程中实施,addExecutionBlock的职务在新开线程中施行。

   

    (3)自定义NSOperation子类--重写main方法就能够

    .h

@interface ZTOperation : NSOperation

@end

    .m

@implementation ZTOperation

- (void)main{

    // 在这里可以自定义任务
    NSLog(@"ZTOperation--%@",[NSThread currentThread]);
}
@end

    ViewController

ZTOperation *zt = [[ZTOperation alloc] init];
[zt start];

    打字与印刷结果:

2017-07-14 14:05:58.824 beck.wang[10389:1490955] ZTOperation--<NSThread: 0x60000007a940>{number = 1, name = main}

    深入分析:任务在主线程中实行,不开启新线程。

 

    2、创制队列

 
  NSOperationQueue总共有三种队列:主队列、其余队列。当中任何队列同期含有了串行、并发成效,通过设置最大并发数maxConcurrentOperationCount来贯彻串行、并发!

  (1)主队列  — 任务在主线程中实施

NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];

    (2)其余队列 — 任务在子线程中实行

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

 

爱博体育app手机版,    3、NSOperation  +  NSOperationQueue (职务增添到行列)

// 添加单个操作:
 - (void)addOperation:(NSOperation *)op;

// 添加多个操作:
- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait NS_AVAILABLE(10_6, 4_0);

// 添加block操作:
- (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);

      代码示例:

- (void)addOperationToQueue
{

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

    // 创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    // 创建NSInvocationOperation
    NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(testRun) object:nil];

    // 创建NSBlockOperation
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"task002 -- %@", [NSThread currentThread]);
    }];

    // 添加操作到队列中: addOperation:
    [queue addOperation:op1];
    [queue addOperation:op2];

    // 添加操作到队列中:addOperationWithBlock:
    [queue addOperationWithBlock:^{
        NSLog(@"task003-----%@", [NSThread currentThread]);
    }];

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

- (void)testRun{
    NSLog(@"task001 -- %@", [NSThread currentThread]);
}

     打印结果:

2017-07-14 14:39:51.669 beck.wang[10536:1516641] start - <NSThread: 0x610000077640>{number = 1, name = main}
2017-07-14 14:39:51.670 beck.wang[10536:1516641] end - <NSThread: 0x610000077640>{number = 1, name = main}
2017-07-14 14:39:51.670 beck.wang[10536:1516686] task003-----<NSThread: 0x600000077200>{number = 3, name = (null)}
2017-07-14 14:39:51.670 beck.wang[10536:1516689] task002 -- <NSThread: 0x61800007e080>{number = 5, name = (null)}
2017-07-14 14:39:51.670 beck.wang[10536:1516687] task001 -- <NSThread: 0x61000007e1c0>{number = 4, name = (null)}

    解析:开启新线程,并发推行。

 

2.1 创立职责

NSOperation是个抽象类,并不可能封装任务。大家唯有选拔它的子类来封装义务,大家有三种方法来封装任务。

a. 使用子类NSInvocationOperation

b. 使用子类NSBlockOperation

c. 定义承继自NSOperation的子类,通过落到实处内部相应的诀窍来封装任务。

在不选取NSOperationQueue,单独接纳NSOperation的状态下系统一起实施操作,上面大家了然一下:

三、NSOperationQueue管理

     1、队列的撤消、暂停、苏醒

         – (void)cancel;
                          NSOperation提供的章程,可撤废单个操作

         –
(void)cancelAllOperations;        
NSOperationQueue提供的形式,能够撤消队列的保有操作

         –
(void)setSuspended:(BOOL)b;  
 可设置任务的暂停和还原,YES代表暂停队列,NO代表恢复生机队列

         –
(BOOL)isSuspended;                判定暂停状态

       
 暂停或收回并不可能使正在实践的操作马上暂停或撤除,而是当前操作实行完后不再实行新的操作。两者的分别在于暂停操作之后还足以过来操作,继续向下实践;而打消操作之后,全体的操作就清空了,不可能再接着实践剩下的操作。

 

     2、最大并发数 maxConcurrentOperationCount

          maxConcurrentOperationCount = -
1  表示不限量,暗中认可并发实行;

          maxConcurrentOperationCount =
1 表示最大并发数为1,串行实行;

          maxConcurrentOperationCount >
([count] > =1)  代表并发实践,min[count,系统限制]。

         代码示例:

- (void)operationQueue
{
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    // 设置最大并发操作数
    // queue.maxConcurrentOperationCount = - 1;  // 并发执行
    // queue.maxConcurrentOperationCount = 1; // 同步执行
     queue.maxConcurrentOperationCount = 2; // 并发执行

    [queue addOperationWithBlock:^{
        NSLog(@"task1-----%@", [NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"task2-----%@", [NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"task3-----%@", [NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"task4-----%@", [NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"task5-----%@", [NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"task6-----%@", [NSThread currentThread]);
    }];
}

     打字与印刷结果:

// queue.maxConcurrentOperationCount = - 1

2017-07-14 15:28:39.554 beck.wang[10772:1557342] task2-----<NSThread: 0x61800006d340>{number = 4, name = (null)}
2017-07-14 15:28:39.554 beck.wang[10772:1557358] task3-----<NSThread: 0x6080000751c0>{number = 5, name = (null)}
2017-07-14 15:28:39.554 beck.wang[10772:1557359] task4-----<NSThread: 0x610000071c00>{number = 6, name = (null)}
2017-07-14 15:28:39.554 beck.wang[10772:1557339] task5-----<NSThread: 0x60000006ea40>{number = 7, name = (null)}
2017-07-14 15:28:39.554 beck.wang[10772:1557340] task1-----<NSThread: 0x608000073500>{number = 3, name = (null)}
2017-07-14 15:28:39.554 beck.wang[10772:1557360] task6-----<NSThread: 0x610000071c80>{number = 8, name = (null)}

// 分析:线程数为6,并发执行

-----------------------------------分割线----------------------------------------------

// queue.maxConcurrentOperationCount =  1

2017-07-14 15:27:04.365 beck.wang[10743:1555231] task1-----<NSThread: 0x60800007c880>{number = 3, name = (null)}
2017-07-14 15:27:04.365 beck.wang[10743:1555231] task2-----<NSThread: 0x60800007c880>{number = 3, name = (null)}
2017-07-14 15:27:04.365 beck.wang[10743:1555231] task3-----<NSThread: 0x60800007c880>{number = 3, name = (null)}
2017-07-14 15:27:04.365 beck.wang[10743:1555231] task4-----<NSThread: 0x60800007c880>{number = 3, name = (null)}
2017-07-14 15:27:04.366 beck.wang[10743:1555231] task5-----<NSThread: 0x60800007c880>{number = 3, name = (null)}
2017-07-14 15:27:04.366 beck.wang[10743:1555231] task6-----<NSThread: 0x60800007c880>{number = 3, name = (null)}

// 分析:线程个数为1,同步执行

-----------------------------------分割线----------------------------------------------

// queue.maxConcurrentOperationCount =  2

2017-07-14 15:18:26.162 beck.wang[10715:1548342] task2-----<NSThread: 0x608000079740>{number = 4, name = (null)}
2017-07-14 15:18:26.162 beck.wang[10715:1548344] task1-----<NSThread: 0x6100000770c0>{number = 3, name = (null)}
2017-07-14 15:18:26.162 beck.wang[10715:1548342] task4-----<NSThread: 0x608000079740>{number = 4, name = (null)}
2017-07-14 15:18:26.162 beck.wang[10715:1548344] task3-----<NSThread: 0x6100000770c0>{number = 3, name = (null)}
2017-07-14 15:18:26.162 beck.wang[10715:1548342] task5-----<NSThread: 0x608000079740>{number = 4, name = (null)}
2017-07-14 15:18:26.163 beck.wang[10715:1548344] task6-----<NSThread: 0x6100000770c0>{number = 3, name = (null)}

// 分析:线程个数为2,并发执行

     很猛烈,通过设置maxConcurrentOperationCount就会完毕产出、串行作用是或不是比GCD轻易多了!

     

     3、操作信赖

   
  NSOperation中大家得以为操作分解为几个小的天职,通过抬高他们之间的信赖关系张开操作,这些平日用到!那也是NSOperation吸引人的地点,不需求像GCD这样接纳复杂的代码完毕,addDependency就可以化解!

- (void)addDependency
{
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        sleep(2);
        NSLog(@"task1-----%@", [NSThread  currentThread]);
    }];
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"task2-----%@", [NSThread  currentThread]);
    }];
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"task3-----%@", [NSThread  currentThread]);
    }];

    // op2依赖于op1 执行顺序op1->op2 必须放在[添加操作队列]之前
    [op2 addDependency:op1];

    // 忌循环依赖 op2已经依赖于op1,切不可再让op1依赖于op2,形成循环依赖
    //[op1 addDependency:op2];

    // 添加操作队列
    [queue addOperation:op1];
    [queue addOperation:op2];
    [queue addOperation:op3];
}

     打字与印刷结果:

2017-07-14 15:46:02.011 beck.wang[10854:1571574] task3-----<NSThread: 0x61800006d740>{number = 3, name = (null)}
2017-07-14 15:46:04.085 beck.wang[10854:1571596] task1-----<NSThread: 0x60000006f040>{number = 4, name = (null)}
2017-07-14 15:46:04.085 beck.wang[10854:1571574] task2-----<NSThread: 0x61800006d740>{number = 3, name = (null)}

    深入分析:task2一定在task1后边实施,因为实践task1前安装了线程等待2s,全部task3最先实施。

 

    4、操作优先级

NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8

   

    5、操作的监听

     
 能够监听一个操作是或不是进行落成,如下载图片,须求在下载第一张图纸后才干下载第二张图纸,这里就足以安装监听。

- (void)addListing{

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

    NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{
        for (int i=0; i<3; i++) {
            NSLog(@"下载图片1-%@",[NSThread currentThread]);
        }
    }];

    // 监听操作的执行完毕
    operation.completionBlock=^{
        // 继续进行下载图片操作
        NSLog(@"--下载图片2--");
    };

    [queue addOperation:operation];
}

     推行结果:

2017-07-14 16:21:43.833 beck.wang[10930:1597954] 下载图片1-<NSThread: 0x61800007a340>{number = 3, name = (null)}
2017-07-14 16:21:43.834 beck.wang[10930:1597954] 下载图片1-<NSThread: 0x61800007a340>{number = 3, name = (null)}
2017-07-14 16:21:43.834 beck.wang[10930:1597954] 下载图片1-<NSThread: 0x61800007a340>{number = 3, name = (null)}
2017-07-14 16:21:43.834 beck.wang[10930:1597955] --下载图片2--

    分析:下载图片1完成后才会实行下载图片2,这里如同知识点3中的加多正视。

 

   
留在最终的话:二十十二线程不只是有GCD!如果您还一向不用过NSOperation,还说怎么吗?赶紧演练起来!当然他们各有各的应用情形,存在即创造!iOS三十二线程的几种技巧GCD、NSThread、NSOperation就都介绍完了,必要精通 GCD、NSThread的能够回头看看小编事先的博客。 

   

2.2 使用子类NSInvocationOperation

// 1.创建NSInvocationOperation对象
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];

// 2.调用start方法开始执行操作
[op start];

- (void)run
{
    NSLog(@"------%@", [NSThread currentThread]);
}

 输出结果:

<NSThread: 0x604000260b00>{number = 1, name = main}

从中能够旁观,在未曾动用NSOperationQueue,单独使用NSOperation的情景下,NSInvocationOperation是在现阶段线程中实施操作,并从未开立异的线程。因为,当前线程是主线程,所以打印出的是主线程。

2.3 使用NSBlockOperation

NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
    // 在主线程
    NSLog(@"------%@", [NSThread currentThread]);
}];

[op start];

出口结果:

<NSThread: 0x604000260b00>{number = 1, name = main}

 从中能够看到,在未有选择NSOperationQueue,单独使用NSOperation的事态下,NSBlockOperation是在主线程中施行操作,并从未创建新的线程。

但是NSBlockOperation还提供了贰个措施
addExecutionBlock:,通过那几个艺术就能够为NSBlockOperation增多额外的操作,那几个额外的操作就能够在别的线程中并发试行。

输出结果

 NSOperation[1326:87276] 3 - <NSThread: 0x6000002715c0>{number = 4, name = (null)}
 NSOperation[1326:87282] 1 - <NSThread: 0x604000271780>{number = 3, name = (null)}
 NSOperation[1326:87200] <NSThread: 0x60000006c6c0>{number = 1, name = main}
 NSOperation[1326:87274] 2 - <NSThread: 0x6000002714c0>{number = 5, name = (null)}

 我们得以看到,任务都以出现推行的,NSBlockOperation中的职务是在主线程中实行的,addExecutionBlock是在新线程中施行的。

2.4 自定义承接NSOperation的子类

WCEOperation.h

#import <Foundation/Foundation.h>

@interface WCEOperation : NSOperation

@end

 WCEOperation.m

#import "WCEOperation.h"

@implementation WCEOperation
// 需要执行的任务
-(void)main{
    for (NSInteger i = 0; i < 5; i++) {
        NSLog(@"%@",[NSThread currentThread]);
    }
}

@end

 在行使的时候,导入这么些文件

WCEOperation *operation = [[WCEOperation alloc] init];
[operation start];

 输出结果:

2017-12-11 22:53:42.126565+0800 NSOperation[1388:90762] <NSThread: 0x60400007fe40>{number = 1, name = main}
2017-12-11 22:53:42.126803+0800 NSOperation[1388:90762] <NSThread: 0x60400007fe40>{number = 1, name = main}
2017-12-11 22:53:42.126946+0800 NSOperation[1388:90762] <NSThread: 0x60400007fe40>{number = 1, name = main}
2017-12-11 22:53:42.127171+0800 NSOperation[1388:90762] <NSThread: 0x60400007fe40>{number = 1, name = main}
2017-12-11 22:53:42.127309+0800 NSOperation[1388:90762] <NSThread: 0x60400007fe40>{number = 1, name = main}

 大家能够看出,在尚未利用NSOperationQueue的情事下,义务都以在主线程中实施的,并从未开启新的线程。

3. NSOperationQueue的主导接纳

和GCD中的并发队列、串行队列略有差别的是:NSOperationQueue
一共有三种队列:主队列、别的队列。其中任何队列相同的时候包含了串行、并发功用。上面是主队列、其他队列的中央创设方法和本性。

– 主队列:

    凡是增多到主队列中的职责(NSOperation),都会放到主线程中实践

NSOperationQueue *queue = [NSOperationQueue mainQueue];

 – 别的队列(非主队列)

    · 加多到这种队列中的任务(NSOperation),就能够活动放到子线程中实行

    · 同一时间蕴涵了:串行、并发功效

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

 4. 将职务到场到行列中

前方说了,NSOperation要求协作NSOperationQueue来实现八线程,那么大家要求将创制好的职务出席到行列中去,总共有三种格局:

a: – (void)addOperation:(NSOperation *)op;

内需先创建职责,再将创建好的职分插手到创设好的连串中去

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

    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"%@ - 1",[NSThread currentThread]);
    }];
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"%@ - 2",[NSThread currentThread]);
    }];
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"%@ - 3",[NSThread currentThread]);
    }];
    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"%@ - 4",[NSThread currentThread]);
    }];
    NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"%@ - 5",[NSThread currentThread]);
    }];
    [opQueue addOperation:op1];
    [opQueue addOperation:op2];
    [opQueue addOperation:op3];
    [opQueue addOperation:op4];
    [opQueue addOperation:op5];

 运营结果:

2017-12-11 23:07:19.203418+0800 NSOperation[1468:97665] <NSThread: 0x60000046ac80>{number = 4, name = (null)} - 4
2017-12-11 23:07:19.203429+0800 NSOperation[1468:97664] <NSThread: 0x604000463300>{number = 6, name = (null)} - 1
2017-12-11 23:07:19.203439+0800 NSOperation[1468:97666] <NSThread: 0x60000046a980>{number = 5, name = (null)} - 2
2017-12-11 23:07:19.203867+0800 NSOperation[1468:97665] <NSThread: 0x60000046ac80>{number = 4, name = (null)} - 5
2017-12-11 23:07:19.204450+0800 NSOperation[1468:97667] <NSThread: 0x604000463280>{number = 3, name = (null)} - 3

 能够看到,NSOperation和NSOperationQueue结合后能够开启新线程,并发实践。

b. – (void)addOperationWithBlock:(void(^)void)block;

不要创立职分,在block中充足职务,直接将任务block参预到行列中。

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

    [opQueue addOperationWithBlock:^{
        NSLog(@"1 - - %@",[NSThread currentThread]);
    }];
    [opQueue addOperationWithBlock:^{
        NSLog(@"2 - - %@",[NSThread currentThread]);
    }];
    [opQueue addOperationWithBlock:^{
        NSLog(@"3 - - %@",[NSThread currentThread]);
    }];
    [opQueue addOperationWithBlock:^{
        NSLog(@"4 - - %@",[NSThread currentThread]);
    }];
    [opQueue addOperationWithBlock:^{
        NSLog(@"5 - - %@",[NSThread currentThread]);
    }];

 运营结果:

2017-12-11 23:17:38.951881+0800 NSOperation[1510:102617] 2 - - <NSThread: 0x600000275400>{number = 4, name = (null)}
2017-12-11 23:17:38.951884+0800 NSOperation[1510:102615] 4 - - <NSThread: 0x6040004655c0>{number = 6, name = (null)}
2017-12-11 23:17:38.951889+0800 NSOperation[1510:102616] 1 - - <NSThread: 0x604000465540>{number = 3, name = (null)}
2017-12-11 23:17:38.951917+0800 NSOperation[1510:102619] 3 - - <NSThread: 0x604000465580>{number = 5, name = (null)}
2017-12-11 23:17:38.952182+0800 NSOperation[1510:102614] 5 - - <NSThread: 0x6000002754c0>{number = 7, name = (null)}

 大家得以见见,都以在新的线程中实行的,并且是出现实践。

5. 操纵串行施行和并行实施的要紧

NSOperationQueue创建的任何队列同不常候兼有串行、并发作用,上面显示了并发功能,那么他的串行功用是何许促成的?

此间就供给使用贰个尤为重要参数:maxConcurrentOperationCount –
最大并发数。也正是最大并且施行的职分数,一般2-3,大于5自此,尽管是在子线程中管理,不过cpu管理过多的子线程,也是有一点都不小恐怕影响主线程。

  • 暗许情状下为 -1,表示不进行限制,默以为并发实施
  • 当maxConcurrentOperationCount为1时,进行串行推行。
  • 当maxConcurrentOperationCount大于1时,举行并发施行,当然这几个值不应超过系统限制,不然固然自身设置四个十分的大的值,系统也会自动调节。

抑或刚刚那多少个例子,大家只设置NSOperationQueue的最大并发数为1

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

    opQueue.maxConcurrentOperationCount = 1;

    [opQueue addOperationWithBlock:^{
        NSLog(@"1 - - %@",[NSThread currentThread]);
    }];
    [opQueue addOperationWithBlock:^{
        NSLog(@"2 - - %@",[NSThread currentThread]);
    }];
    [opQueue addOperationWithBlock:^{
        NSLog(@"3 - - %@",[NSThread currentThread]);
    }];
    [opQueue addOperationWithBlock:^{
        NSLog(@"4 - - %@",[NSThread currentThread]);
    }];
    [opQueue addOperationWithBlock:^{
        NSLog(@"5 - - %@",[NSThread currentThread]);
    }];

 输出结果:

2017-12-11 23:22:30.824859+0800 NSOperation[1535:105237] 1 - - <NSThread: 0x600000275cc0>{number = 3, name = (null)}
2017-12-11 23:22:30.825228+0800 NSOperation[1535:105238] 2 - - <NSThread: 0x600000275d00>{number = 4, name = (null)}
2017-12-11 23:22:30.825614+0800 NSOperation[1535:105238] 3 - - <NSThread: 0x600000275d00>{number = 4, name = (null)}
2017-12-11 23:22:30.826585+0800 NSOperation[1535:105250] 4 - - <NSThread: 0x6000002756c0>{number = 5, name = (null)}
2017-12-11 23:22:30.826851+0800 NSOperation[1535:105250] 5 - - <NSThread: 0x6000002756c0>{number = 5, name = (null)}

 能够看看,当最大并发数为1的时候,职分是按梯次串行推行的,当最大并发数为2时,职务是出现试行的,并且张开线程数量是由系统调节的。

6. 操作依赖

NSOperation和NSOperationQueue最吸引认得地方是它能加上操作之间的正视关系。比方有A和B五个操作,在那之中A施行完操作,B手艺进行操作,那么就供给让B重视于A:

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

    NSBlockOperation *opA = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"我是opA,我先执行 - %@",[NSThread currentThread]);
    }];

    NSBlockOperation *opB = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"我是opB,我后执行 - %@",[NSThread currentThread]);
    }];

    [opB addDependency:opA];

    [opQueue addOperation:opB];
    [opQueue addOperation:opA];

 输出结果:

2017-12-11 23:31:23.494225+0800 NSOperation[1569:109435] 我是opA,我先执行 - <NSThread: 0x604000079ec0>{number = 3, name = (null)}
2017-12-11 23:31:23.494688+0800 NSOperation[1569:109434] 我是opB,我后执行 - <NSThread: 0x60000046f2c0>{number = 4, name = (null)}

 能够看到,无论运维三次,其结果都以opA先进行,opB后实行。注意:不能够opA依赖opB,同期opB重视opA。职责实行的种种,并不在于增添的各类,实施的逐个取决于依赖。

7. 别的的主意

// NSOperation提供的方法,可取消单个操作
- (void)cancel;

// NSOperationQueue提供的方法,可以取消队列的所有操作
- (void)cancelAllOperations;

// 可以设置任务的暂停和恢复,YES代表暂停队列,No表示恢复队列。
- (void)setSuspended:(BOOL)b;

// 判断暂停状态
- (BOOL)isSuspended;

// 设置操作优先级 优先级越高,被调用的几率越大

- (NSOperationQueuePriority)queuePriority;
- (void)setQueuePriority:(NSOperationQueuePriority)p;

 注意:


这里的中断和撤消并不表示可以将前段时间的操作立刻撤回,而是当当前的操作实行完成后不复实行新的操作。


暂停和注销的区分在于:暂停操作之后还足以还原操作,继续向下实行;而撤销操作之后,全数的操作就清空了,无法再跟着试行剩下的操作。

相关文章