iOS学习笔记OSiOS异步多线程iOS开发常用知识点

认识和使用NSOperation

2015-07-12  本文已影响6226人  CoderAO

NSOperation是OC中多线程技术的一种,是对GCD的OC包装.它包含队列(NSOperationQueue)操作(NSOperation)两个基本要素.

通过这篇文章你可以了解到:

怎样使用NSOperation

使用

NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task) object:nil];
// 调用start方法执行操作op操作
[op start];
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"task0---%@", [NSThread currentThread]);
}];
[op start];

根据打印的结果我们会发现,直接调用start方法时,系统并不会开辟一个新的线程去执行任务,任务会在当前线程同步执行.

注意: 这里我们说的是当前线程而非主线程,意即:如果是在主线程中调用op的start方法,那么该任务是在主线程中执行;但如果是在其他子线程调用start方法,任务则是在其他子线程执行.

当然NSBlockOperation还有一种使用方法addExecutionBlock:使得我们可以给其添加更多的操作,使用如下:

NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"task0---%@", [NSThread currentThread]);
}];

[op addExecutionBlock:^{
    NSLog(@"task1----%@", [NSThread currentThread]);
}];

[op addExecutionBlock:^{
    NSLog(@"task2----%@", [NSThread currentThread]);
}];

// 开始必须在添加其他操作之后
[op start];

由打印的结果发现: task0的结果和前面的结论一样,是执行在主线程中的(因为是在主线程中调用start方法),但task1和task2都是在自己的新线程中执行.也就是说:当NSBlockOperation封装的操作数大于1的时候,就会执行异步操作.

自定义NSOperation的方法也很简单,我们需要做到下面几个步骤:

1.子类化NSOperation

2.在.m文件里面实现-(void)main方法

3.初始化该操作的时候直接调用alloc及init即可

4.同样可以通过start方法让你自定义的任务跑在当前线程中

关键代码:

自定义NSOperation的实现文件:

#import "AROperation.h"
@implementation AROperation
- (void)main {
    NSLog(@"this is my custom operation ---- %@", [NSThread currentThread]);
}
@end

使用(在任何需要启用该任务的地方):

// 该操作被执行时就会执行op内部定义的任务
AROperation *op = [[AROperation alloc] init];
[op start];

怎样使用NSOperationQueue

NSOperation的start方法默认是同步执行任务,这样的使用并不多见,只有将NSOperation与NSOperationQueue进行结合,才会发挥出这种多线程技术的最大功效.当NSOperation被添加到NSOperationQueue中后,就会全自动地执行异步操作.

设置NSOperationQueue的最大并发数

NSOperationQueue可以通过以下方法设置最大并发数,
setMaxConcurrentOperationCount:,值得注意的是:**当并发数为1就变成了串行执行任务
**

NSOperationQueue的暂停恢复和取消

因此, 我们在自定义NSOperation的时候需要注意,最好可以经常通过判断isCancelled方法检测操作是否被取消,以响应外部可能进行的取消操作.如:

// 自定义NSOperation类.m文件的main方法实现
- (void)main {
    for (NSInteger i = 0; i < 1000; i++) {
        NSLog(@"SubTask---0---%zd",i);
    }
    // 判断当前任务是否被取消,如果已经取消,及时返回
    if (self.cancelled) {
        return;
    }

    for (NSInteger i = 0; i < 1000; i++) {

        NSLog(@"SubTask---1---%zd", i);
    }
    if (self.cancelled) {
        return;
    }

    for (NSInteger i = 0; i < 1000; i++) {
        NSLog(@"SubTask---2---%zd",i);
    }
}

添加依赖和监听

[op3 addDependency:op1];
[op3 addDependency:op2];

表示op3会在op1和op2都执行完毕后才执行

添加依赖的时候要注意防止添加循环依赖,此外我们还可以在不同队列的operation之间添加依赖

线程间通信

有时我们在子线程中执行完一些操作的时候,需要回到主线程做一些事情(如进行UI操作),因此需要从当前线程回到主线程,以下载并显示图片为例,方法如下:

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 子线程下载图片
[queue addOperationWithBlock:^{
    NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
    NSData *data = [NSData dataWithContentsOfURL:url];
    UIImage *image = [[UIImage alloc] initWithData:data];
    // 回到主线程进行显示
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        self.imageView.image = image;
    }];
}];

NSOperation的使用还是比较简单的,但是要注意的细节比较多,一些方法比较容易被忽略,于是乎特此总结一下.这里就不上传示例代码了,有问题的童鞋可以直接留言.

上一篇下一篇

猜你喜欢

热点阅读