简介
iOS有三种多线程编程的技术分别是NSThread 、Cocoa NSOperation、GCD,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的。在前面呢我对GCD和NSThread的基本使用做过一些简单的总结,大家有空可以看看。
NSOperation和NSOperationQueue其实也是IOS多线程推荐使用的方法之一,很多网络框架底层的实现原理也都是通过这种方式实现的。但是自己使用的话我还是推荐使用GCD或者NSThread之一,不过也不一定,开发者也可根据自己的使用习惯自己选择用什么方式来实现。因为其实三种方式都是比较简单的,但是就我个人而言,GCD、NSThread是我比较喜欢使用的。在这里我先对NSOperation的使用方式做一些简单的总结,以后用到了再来完善这篇文章。
NSOperation流程
1)先将需要执行的操作封装到一个NSOperation对象中
2)然后将NSOperation对象添加到NSOperationQueue中
3)系统会自动将NSOperationQueue中的NSOperation取出来
4)将取出的NSOperation封装的操作放到另外一条新线程中执行
NSOperation
NSOperation本身是抽象基类,因此必须使用它的子类,使用NSOperation子类的方式有2种:
1、Foundation框架提供了两个具体子类直接供我们使用:NSInvocationOperation和NSBlockOperation
2、自定义子类继承NSOperation,实现内部相应的方法(重写main方法)
3、执行操作:NSOperation调用start方法即可开始执行操作,NSOperation对象默认按同步方式执行,也就是在调用start方法的那个线程中直接执行。NSOperation对象的isConcurrent方法会告诉我们这个操作相对于调用start方法的线程,是同步还是异步执行。isConcurrent方法默认返回NO,表示操作与调用线程同步执行
4、取消操作:operation开始执行之后, 默认会一直执行操作直到完成,我们也可以调用cancel方法中途取消操作
1 2
| NSOperation *operation = [[NSOperation alloc] init]; [operation cancel];
|
5、监听操作的执行:如果我们想在一个NSOperation执行完毕后做一些事情,就调用NSOperation的setCompletionBlock方法来设置想做的事情
NSInvocationOperation使用
NSInvocationOperation有两种启动方式
第一种
1 2 3 4 5 6
| NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(todo:) object:kURL]; //将operation加入到NSOperationQueue系统自动执行 NSOperationQueue *queue = [[NSOperationQueue alloc]init]; [queue addOperation:operation];
|
第二种
1 2 3 4 5 6 7
| //NSOperation:抽象类,不具备封装功能 //创建操作对象,封装要执行的任务 //NSInvocationOperation 封装操作 NSInvocationOperation *operation=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test) object:nil]; //执行操作 [operation start];
|
注意:以上两种方式虽然都可以实现启动,但是他们是有区别的。操作对象默认在主线程中执行,只有添加到队列中才会开启新的线程。即默认情况下,如果操作没有放到队列中queue中,都是同步执行。只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作,明白了吧,第一种异步执行,第二种同步执行。
NSBlockOperation使用
能够并发地执行一个或多个block对象,所有相关的block都执行完之后,操作才算完成
创建并执行操作,其实它和NSInvocationOperation很类似,这里就不再很多的介绍了,因为启动都是类似的。
1 2 3 4 5 6 7
| NSBlockOperation *blockOper =[NSBlockOperation blockOperationWithBlock:^(void){ NSLog(@"执行了一个新的操作,线程:%@", [NSThread currentThread]); }]; //开始执行任务(这里还是同步执行) [blockOper start];
|
通过addExecutionBlock方法添加block操作
1 2 3 4 5 6 7 8 9 10 11 12 13
| [blockOper addExecutionBlock:^(void){ NSLog(@"又执行了1个新的操作,线程:%@", [NSThread currentThread]); }]; [blockOper addExecutionBlock:^() { NSLog(@"又执行了1个新的操作,线程:%@", [NSThread currentThread]); }]; [blockOper addExecutionBlock:^() { NSLog(@"又执行了1个新的操作,线程:%@", [NSThread currentThread]); }]; [blockOper start];
|
可以看出,这4个block是并发执行的,也就是在不同线程中执行的,其中num属性可以看成是线程的id
,只要NSBlockOperation封装的操作数大于1,就会异步执行操作
NSOperation加入NSOperationQueue 的使用情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| - (void)viewDidLoad { [super viewDidLoad]; //创建NSInvocationOperation对象,封装操作 NSInvocationOperation *operation1=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test1) object:nil]; NSInvocationOperation *operation2=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test2) object:nil]; //创建对象,封装操作 NSBlockOperation *operation3=[NSBlockOperation blockOperationWithBlock:^{ NSLog(@"NSBlockOperation3--1----%@",[NSThread currentThread]); }]; [operation3 addExecutionBlock:^{ NSLog(@"NSBlockOperation3--2----%@",[NSThread currentThread]); }]; //创建NSOperationQueue NSOperationQueue * queue=[[NSOperationQueue alloc]init]; //把操作添加到队列中 [queue addOperation:operation1]; [queue addOperation:operation2]; [queue addOperation:operation3]; } -(void)test1 { NSLog(@"NSInvocationOperation--test1--%@",[NSThread currentThread]); } -(void)test2 { NSLog(@"NSInvocationOperation--test2--%@",[NSThread currentThread]); }
|
系统自动将NSOperationqueue中的NSOperation对象取出,将其封装的操作放到一条新的线程中执行。上面的代码示例中,一共有四个任务,operation1和operation2分别有一个任务,operation3有两个任务。一共四个任务,开启了四条线程。队列的取出是有顺序的,与打印结果并不矛盾。这就好比,选手A,BC虽然起跑的顺序是先A,后B,然后C,但是到达终点的顺序却不一定是A,B在前,C在后。
自定义重写方法。。。。。。待续。。。。。。