在iOS中开发,涉及到多线程的时候,基本常用的方法有NSThread、GCD和NSOperation类。苹果比较推荐的是使用NSOperation来开发多线程应用。下面就介绍NSOperation的用法。
NSOperation是GCD的高级抽象,在iOS多线程开发中,NSOperation更是好用,它是以一种面向对象的方法来异步执行任务的。
NSOperation实现多线程编程比较方便,它能够将我们要执行的操作给封装起来。我们将需要执行的操作封装到NSOperation对象后,再将NSOperation对象添加到NSOperationQueue中,系统就会自动将NSOperation中封装的操作放到一条新线程中执行,看起来蛮简单的。
不过NSOperation是一个抽象类,我们不能直接用。需要用它的子类来实现封装动作,其实现方法有3种:
- NSInvocationOperation
- NSBlockOperation
- 自定义子类继承NSOperation,实现内部相应的⽅法
NSOperation可以调⽤start⽅法来执⾏任务,但默认是同步执行的。如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作。
NSOperation
先来看看NSOperation。首先看看不用自定义继承nsoperation封装操作的方法,有两个子类供我们用:NSInvocationOperation和NSBlockOperation。用法如下:
//NSInvocationOperation
- (void)invocationOperation{
NSInvocationOperation *myOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operation) object:nil];
//开启任务
[myOperation start];
}
-(void)operation{
NSLog(@"-----invocationOperation----:%@",[NSThread currentThread]);
}
通过调用[self invocationOperation]执行,然后会发现打印信息:
可以看到当前任务的线程是在主线程中。
同样的,如果运用NSBlockOperation:
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"-----blockOperation----:%@",[NSThread currentThread]);
}];
[op start];
打印出的结果一样也是在主线程中:
不过在NSBlockOperation类中有另一个方法addExecutionBlock:
这个方法可以往NSBlockOperation对象中添加其他的任务,比如多添加几个:
[op addExecutionBlock:^{
NSLog(@"-----blockOperation2----:%@",[NSThread currentThread]);
}];
[op addExecutionBlock:^{
NSLog(@"-----blockOperation3----:%@",[NSThread currentThread]);
}];
[op addExecutionBlock:^{
NSLog(@"-----blockOperation4----:%@",[NSThread currentThread]);
}];
这时候就有多条线程了。
接下来看自定义的NSOperation:
#import "CustomOperation.h"
@implementation CustomOperation
//重写main方法
- (void)main{
//放要执行的任务
NSLog(@"-----CustomOperation----:%@",[NSThread currentThread]);
}
@end
自定义的NSOperation子类需要复写main方法,这个方法里就放要执行的任务。然后在需要用的地方生成CustomOperation对象:
CustomOperation *cp = [[CustomOperation alloc] init];
[cp start];
打印信息:
NSOperationQueue
接下来看NSOperationQueue,将NSOperation添加到NSOperationQueue中就能实现异步操作了。
先看看NSOperationQueue中有哪些方法:
基本有三种添加任务的方式。用起来如下:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSInvocationOperation *myOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operation) object:nil];
[queue addOperation:myOperation];
[queue addOperationWithBlock:^{
NSLog(@"-----blockOperation----:%@",[NSThread currentThread]);
}];
可以看到,当任务添加进队列的时候即开始执行,不用再调用start方法了。并且都是在不同的线程中。另外,NSOperationQueue默认创建的是并行队列。
NSOperation线程通信和任务依赖
线程通信一般用到的就是子线程中处理耗时操作获取网络数据,然后在主线程中赋给UI:
[queue addOperationWithBlock:^{
//耗时操作
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
//主线程中要执行的
}];
}];
任务依赖就是如果任务A依赖任务B,就是要等B执行完后才去执行A。可以这样处理:
//比如有bp1和bp2任务
NSBlockOperation *bp1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"-----1----:%@",[NSThread currentThread]);
}];
NSBlockOperation *bp2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"-----2----:%@",[NSThread currentThread]);
}];
//bp1依赖bp2,所以bp2先执行完后再执行bp1
[bp1 addDependency:bp2];
[queue addOperation:bp1];
[queue addOperation:bp2];