您的位置:首页 > 移动开发 > IOS开发

iOS多线程学习之NSOperation(一)

2015-09-05 23:39 411 查看
什么是NSOperation呢?有什么用呢?和GCD相比有什么不同呢?或者优势呢?

NSOperation底层实现是基于GCD的,比GCD多了一些简单使用的功能,使用更加面向对象

作用:配合使用NSOperation 和 NSOperationQueue也能实现多线程

NSOperation 和 NSOperationQueue实现多线程的步骤:

(1)将需要的任务先封装到一个NSOperation对象中(GCD封装在block中)

(2)然后将NSOperation添加到NSOperationQueue对象中(GCD将block添加到队列中)

(3)系统自动将NSOperationQueue中的NSOperation取出来

(4)将取出的NSOperation封装的操作放到一条新线程中执行

在使用之前还要说下:NSOperation是一个抽象类,所谓抽象类就是没什么功能的类,并不具备封装操作的能力,抽象么,具体不出来,能有啥用,只能靠想象了,但这是实际操作写代码啊,不是想想啊,所以我们就要用到它的子类了,换句话说,他的子类不抽象,可以实现封装操作

使用NSOperation子类的三种方式:

(一)NSInvocationOperation

(二)NSBlockOperation

(三)自定义子类继承NSOperation,实现内部相应的方法

下面意义列举

(一)NSInvocationOperation(这个功能基本很少用,为什么呢,下面看看就知道了)

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

[self invocationQueue];

}

- (void)invocationQueue {

NSInvocationOperation * invoQueue = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil];
[invoQueue start];
}

- (void)download {

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

@end


通过打印发现,这个操作在主线程中运行的,也就是调用start方法没有开辟线程,直接变成同步(在当前线程)执行了,写了这么一大堆,然并卵,还不如直接调用[self downLoad]呢,那么下面我们想另开线程应该怎么做呢?犹如上面的步骤说明,把任务添加到NSOperationQueue对象中:

- (void)invocationQueue {

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

NSInvocationOperation * invoQueue = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil];
//[invoQueue start];
[queue addOperation:invoQueue];
}

- (void)download {

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

@end


通过打印发现不是num!=1,不是主线程,添加到队列中,会自动异步执行

即使这样也感觉比较垃圾,还不如直接用NSThread呢,下面看看另一种方法

- (void)viewDidLoad {
[super viewDidLoad];

//[self invocationQueue];
[self blockQueue];

}

- (void)blockQueue {

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


通过上面可以知道调用start是同步执行,打印出来的结果是num=1,在主线程,但是也有一点不同,在添加几个任务,再看看打印结果

- (void)viewDidLoad {
[super viewDidLoad];

//[self invocationQueue];
[self blockQueue];

}

- (void)blockQueue {

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

[bkOperation addExecutionBlock:^{
NSLog(@"loadImage2---%@", [NSThread currentThread]);
}];
[bkOperation addExecutionBlock:^{
NSLog(@"loadImage3---%@", [NSThread currentThread]);
}];
[bkOperation start];

}


打印结果多了两个线程,由此可以得知,当通过start执行任务数大于1时会开启异步线程,但是1还是在主线程,这个也很少用,另外就是面试业主要问队列,下面我们就用队列:

- (void)blockQueue {

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

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

[bkOperation addExecutionBlock:^{
NSLog(@"loadImage2---%@", [NSThread currentThread]);
}];
[bkOperation addExecutionBlock:^{
NSLog(@"loadImage3---%@", [NSThread currentThread]);
}];

[queue addOperation:bkOperation];
//[bkOperation start];

}


通过打印结果就可以知道我们将任务放到队列中后就会异步执行了,也可以这样写:

- (void)blockQueue {

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

[bkOperation addExecutionBlock:^{
NSLog(@"loadImage12---%@", [NSThread currentThread]);
}];
NSBlockOperation * bkOperation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage2---%@", [NSThread currentThread]);
}];
NSBlockOperation * bkOperation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage3---%@", [NSThread currentThread]);
}];
NSBlockOperation * bkOperation4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage4---%@", [NSThread currentThread]);
}];
NSBlockOperation * bkOperation5 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage4---%@", [NSThread currentThread]);
}];

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

[queue addOperation:bkOperation];
[queue addOperation:bkOperation1];
[queue addOperation:bkOperation3];
[queue addOperation:bkOperation4];
[queue addOperation:bkOperation5];
//[bkOperation start];

}


(三)NSOperationQueue

- (void)viewDidLoad {
[super viewDidLoad];

//[self invocationQueue];
// [self blockQueue];
[self opeationQueue];
}

- (void)opeationQueue {

//创建一个队列(非主队列)
NSOperationQueue * queue = [[NSOperationQueue alloc] init];

//添加操作到队列中(自动并发执行,和GCD的Global Dispatch Queue相似)
NSBlockOperation * blockQueue1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage2---%@", [NSThread currentThread]);
}];
NSBlockOperation * blockQueue2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage2---%@", [NSThread currentThread]);
}];
[queue addOperation:blockQueue1];
[queue addOperation:blockQueue2];

}


解释:先把block里面的操作包装成operation对象,在把这个对象添加到队列中,block中的任务就是在异步线程中执行,其实这样写还是有点麻烦,我们可以通过queue一步写到位:

- (void)opeationQueue {

//创建一个队列(非主队列)
NSOperationQueue * queue = [[NSOperationQueue alloc] init];

//添加操作到队列中(自动并发执行,和GCD的Global Dispatch Queue相似)
NSBlockOperation * blockQueue1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage1---%@", [NSThread currentThread]);
}];
NSBlockOperation * blockQueue2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage2---%@", [NSThread currentThread]);
}];
[queue addOperation:blockQueue1];
[queue addOperation:blockQueue2];
[queue addOperationWithBlock:^{
NSLog(@"loadImage3---%@", [NSThread currentThread]);
}];
}


通过打印我们就发现三个线程,说白点,就是有三个operation对象,只不过最后一个block内部帮我们封装了,而前两个是我们自己创建的

所以我们搞个任务想异步执行,可以直接用最后一个方式了。
- (void)viewDidLoad {
[super viewDidLoad];

//[self invocationQueue];
// [self blockQueue];
[self opeationQueue];
}

- (void)opeationQueue {

//创建一个队列(非主队列)
NSOperationQueue * queue = [[NSOperationQueue alloc] init];

//添加操作到队列中(自动并发执行,和GCD的Global Dispatch Queue相似)
//    NSBlockOperation * blockQueue1 = [NSBlockOperation blockOperationWithBlock:^{
//        NSLog(@"loadImage1---%@", [NSThread currentThread]);
//    }];
//    NSBlockOperation * blockQueue2 = [NSBlockOperation blockOperationWithBlock:^{
//        NSLog(@"loadImage2---%@", [NSThread currentThread]);
//    }];
//    [queue addOperation:blockQueue1];
//    [queue addOperation:blockQueue2];
[queue addOperationWithBlock:^{
NSLog(@"loadImage3---%@", [NSThread currentThread]);
}];
}


上面是基本用法:

添加操作到队列中有两种方法:

- (void)addOperation:(NSOperation *)op;

- (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);
(点进NSOperationQueue官方文档也可以看到这两个方法)

那么高级一点的用法又长啥样啊?怎么用?先看一下下面执行的结果

- (void)opeationQueue {

//创建一个队列(非主队列)
NSOperationQueue * queue = [[NSOperationQueue alloc] init];

//添加操作到队列中(自动并发执行,和GCD的Global Dispatch Queue相似)
NSBlockOperation * blockQueue1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage1---%@", [NSThread currentThread]);
}];
NSBlockOperation * blockQueue2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage2---%@", [NSThread currentThread]);
}];
NSBlockOperation * blockQueue3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage2---%@", [NSThread currentThread]);
}];
NSBlockOperation * blockQueue4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage2---%@", [NSThread currentThread]);
}];
NSBlockOperation * blockQueue5 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage2---%@", [NSThread currentThread]);
}];
[queue addOperation:blockQueue1];
[queue addOperation:blockQueue2];
[queue addOperation:blockQueue3];
[queue addOperation:blockQueue4];
[queue addOperation:blockQueue5];

}


打印发现,我靠,多少个任务多少条线程啊,假如我们几百个任务开了几百条线程,不用我说,你也知道占用内存太多了,太浪费资源了,而GCD内部会帮我们自动管理线程条数,最多也就4、5条,但是这是系统决定的,我们操作不了,那么我们NSOperationQueue可不可以控制线程个数来提高性能呢?答案是可以,下面我们可以设置一下最大并发数:

- (void)opeationQueue {

//1.创建一个队列(非主队列)
NSOperationQueue * queue = [[NSOperationQueue alloc] init];

//2.设置最大并发数
queue.maxConcurrentOperationCount = 2;

//3.添加操作到队列中(自动并发执行,和GCD的Global Dispatch Queue相似)
NSBlockOperation * blockQueue1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage1---%@", [NSThread currentThread]);
}];
NSBlockOperation * blockQueue2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage2---%@", [NSThread currentThread]);
}];
NSBlockOperation * blockQueue3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage2---%@", [NSThread currentThread]);
}];
NSBlockOperation * blockQueue4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage2---%@", [NSThread currentThread]);
}];
NSBlockOperation * blockQueue5 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"loadImage2---%@", [NSThread currentThread]);
}];
[queue addOperation:blockQueue1];
[queue addOperation:blockQueue2];
[queue addOperation:blockQueue3];
[queue addOperation:blockQueue4];
[queue addOperation:blockQueue5];

}


通过打印结果我们可以看到上面任务仅在两条线程中执行(是指同一时间开的执行任务的线程数)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: