上篇文章写到GCD,GCD的优点是我们只需要定义想要执行的任务并追加到适当的Dispatch Queue中,GCD负责生成线程、计划执行任务并管理线程的生命周期,其线程管理是作为系统的一部分来实现的,因此可统一管理,所以效率很高,而且形式上十分简洁。
GCD看似很完美了,但是GCD是基于C语言开发的,而NSOperation是基于GCD且面向对象的技术,比GCD多了一些简单实用的功能。虽然NSOperation会增加额外的开销,但是更加灵活。NSOperation对应GCD的任务,NSOperationQueue对应GCD的队列。
NSOperation
NSOperation是一个抽象类,我们创建需要执行的任务时,需要使用其子类。Apple为我们定义了两个NSOperation的子类:NSInvocationOperation和NSBlockOperation,另外我们可以自定义NSOperation的子类。
NSOperationQueue
有两种NSOperationQueue:
主队列:通过下面方法获取,放到主队列的任务在主线程执行。
NSOperationQueue*queue = [NSOperationQueuemainQueue];
非主队列:
NSOperationQueue*queue = [[NSOperationQueuealloc]init];
非主队列既可以并发执行任务也可以串行执行任务,通过设置最大并发数来控制。最大并发数默认为-1,表示不受限制,如果最大并发数为1则是串行队列。非主队列无论是并发队列还是串行队列都不在主线程中执行。
NSOperation可以调用start方法来执行任务,而不用加入到NSOperationQueue中,但是该任务将会在当前线程同步执行。
NSInvocationOperation
NSInvocationOperation *io = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationTest) object:nil];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:io];
- (void)invocationTest {
for(int i =0; i <100; i++) {
NSLog(@"mainThread: %@, currentThread: %@", [NSThreadmainThread], [NSThreadcurrentThread]);
}
}
NSBlockOperation
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *bo = [NSBlockOperation blockOperationWithBlock:^ {
for(int i =0; i <100; i++) {
NSLog(@"%@",[NSThread currentThread]);
}
}];
[queue addOperation:bo];
自定义非并发的NSOperation子类:
我们要自定义初始化方法,并重写- (void)main {};方法,在此方法中需要能相应取消时间。
其余方法:
NSBlockOperation的addExecutionBlock方法:
NSBlockOperation *blockOperation = [NSBlockOperationblock OperationWithBlock:^{
NSLog(@"block1 : currentThread: %@", [NSThread currentThread]);
sleep(3);
}];
[blockOperation addExecutionBlock:^{
NSLog(@"block2 : currentThread: %@", [NSThread currentThread]);
sleep(3);
}];
[blockOperation addExecutionBlock:^{
NSLog(@"block3 : currentThread: %@", [NSThread currentThread]);
sleep(3);
}];
[blockOperation start];
结果:Block1是在主线程中执行的,block2和block3不是。
添加依赖:
[io addDependency:bo];
io会在bo执行完后执行,不同队列的operation之间可以添加依赖。
可通过下面方法执行operation完毕后的操作。
io.completionBlock= ^{
NSLog(@"finish");
};
我们经常需要在非主线程完成后回到主线程刷新UI:
NSBlockOperation *bo = [NSBlockOperation blockOperationWithBlock:^ {
for(inti =0; i <100; i++) {
NSLog(@"%@",[NSThread currentThread]);
}
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"=====%@",[NSThreadcurrentThread]);
}];;
}];
暂停任务:
queue.suspended = YES;
恢复任务:
queue.suspended=NO;
取消所有任务,一旦取消不可逆
[queue cancelAllOperations];
暂停和取消只能暂停或取消处于等待状态的任务,不能暂停或取消正在执行中的任务