NSOperation的作用:
配合使用NSOperation和NSOperationQueue能实现多线程编程.
NSOperation和NSOperationQueue能实现多线程的具体步骤
1.首先需要将执行的操作封装到一个NSOperation对象中(我们称之为 任务)
2.然后将NSOperation对象加到NSOperationQueue中
3.系统会自动将NSOperationQueue中的NSOperation取出来
4.将取出的NSOperation封装的操作放在一条新线程
中执行
NSOperation的子类
1.NSOperation是一个抽象类,不具备封装操作的能力,必须使用它的子类
2.使用NSOperation子类的方式有3种
1>NSInvocationOperation
2>NSBlockOperation
自定义子类继承NSOperation,实现内部相应的方法
虽然NSOperation较GCD比较而言,有点繁琐,但是它能够自由的控制任务的执行,而且经过测试,它的稳定性比较高.
好了现在介绍:自定义NSOperation的方式来添加任务
自定义类,继承于NSOperation
// NSOperation内部有这个方法, 是用来专门,封装任务体的
// 默认情况下如果直接调用start的时候,不会新开一条新线程去执行操作
- (void)main
{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"我爱你 ------ %@", [NSThread currentThread]);
}
利用NSInvocationOperation来添加任务
1.创建NSInvocationOperation对象
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run:) object:@"我爱你"];
2.调用start方法开始执行操作
- (void)start
一点执行这个操作,就会调用target的sel的方法
3.注意
1>默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作
2>只有将NSOperation放在一个NSOperationQueue中,才会异步执行操作
利用NSBlockOperation来添加任务
1.创建NSBlockOperation对象
2.通过addExecutionBlock:方法添加更多的操作
3.注意:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作
// block 直接将 操作封装在 block中 ,执行的。 会进行并行操作,并且第一条操作 安排在主线程。 不必指定 target
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"ლ(′◉❥◉`ლ)----%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"我爱你----%@",[NSThread currentThread]);;
}];
[operation addExecutionBlock:^{
NSLog(@"我爱你----%@",[NSThread currentThread]);;
}];
[operation addExecutionBlock:^{
NSLog(@"我爱你----%@",[NSThread currentThread]);;
}];
// 调用 start 统一开始执行任务
[operation start];
控制台输出:
NSOperationQueue
NSOperationQueue的作用
1.NSOperation可以调用start方法来执行任务,但默认是同步执行的
2.如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作
添加操作(任务)到NSOperationQueue中 (需要注意的是,一旦加入队列,任务就会被执行.)
1.添加任务对象到队列中
- (void)addOperation:(NSOperation *)op
2.添加任务'block'到队列,直接执行
- (void)addOperationWithBlock:(void (^)(void))block
// 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//
__block UIImage *image1;
NSBlockOperation *block1 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:2.0];
NSURL *url = [NSURL URLWithString:@"http://fc.topit.me/c/4f/99/11922014783d4994fco.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
image1 = [UIImage imageWithData:data];
NSLog(@"1------%@",[NSThread currentThread]);
}];
__block UIImage *image2;
NSBlockOperation *block2 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:2.0];
NSURL *url = [NSURL URLWithString:@"http://cdn.duitang.com/uploads/item/201311/25/20131125164036_NUAC8.jpeg"];
NSData *data = [NSData dataWithContentsOfURL:url];
image2 = [UIImage imageWithData:data];
NSLog(@"2------%@",[NSThread currentThread]);
}];
NSBlockOperation *block3 = [NSBlockOperation blockOperationWithBlock:^{
UIGraphicsBeginImageContext(CGSizeMake(200, 200));
[image1 drawInRect:CGRectMake(0, 50, 200, 150)];
[image2 drawInRect:CGRectMake(0, 0, 200, 50)];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// 回到主队列 , 进行UI赋值
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}];
}];
// addDependency 添加依赖 , 前俩个 ,执行完了之后 最后一个再执行。
[block3 addDependency:block1];
[block3 addDependency:block2];
[queue addOperation:block1];
[queue addOperation:block2];
[ queue addOperation:block3 ];
// // 先让执行 block1, block2 (异步并发执行) ,在进行 block3 的执行
// [queue addOperations:@[block1,block2] waitUntilFinished:YES];
// [queue addOperation:block3];
//
几种常见的属性和方法
1.最大并发数(同时执行的任务数) 最大并发数一般都是系统给出,我任务,系统并发送是系统根据它的性能, 给分配的线程,如果性能高,可能多分点. 至于并发送内部怎么执行 ,系统自行做决定, 它认为哪条线程空闲,他就会把哪条线程交给你
- (NSInteger)maxCurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt
有些人,会陷入误区, 如果设置了最大并发数是1,那么系统就只会创建一条线程, 因为 同一时间只允许一条线程执行任务, 但是这种想法是错误的, 系统只是保持同一时间执行任务是一条线程, 但没表示 换个时间就不能换线程
// 默认不设置并发数的时候, 异步执行, 创建多条线程
let queue = NSOperationQueue()
queue.addOperationWithBlock { () -> Void in
print("1------\(NSThread.currentThread())")
}
queue.addOperationWithBlock { () -> Void in
print("1------\(NSThread.currentThread())")
}
queue.addOperationWithBlock { () -> Void in
print("1------\(NSThread.currentThread())")
}
queue.addOperationWithBlock { () -> Void in
print("1------\(NSThread.currentThread())")
}
queue.addOperationWithBlock { () -> Void in
print("1------\(NSThread.currentThread())")
}
queue.addOperationWithBlock { () -> Void in
print("1------\(NSThread.currentThread())")
}
queue.addOperationWithBlock { () -> Void in
print("1------\(NSThread.currentThread())")
}
queue.addOperationWithBlock { () -> Void in
print("1------\(NSThread.currentThread())")
}
***添加
queue.maxConcurrentOperationCount = 1
可以看出来, 线程并不是一样的. 所以最大并发数的理解, 应该是我上面指出的
2.队列的取消,暂停,和恢复
1>取消队列的所有操作
- (void)cancelAllOpertions
注意: 也可以调用NSOperation的-(void)cancel方法取消单个操作. (总感觉单个任务取消不掉)
2>暂停和恢复队列
- (void)setSuspended:(BOOL)b
// YES 代表暂停队列,NO代表恢复队列
- (BOOL)isSuspended
操作依赖
首先依赖其他的线程中也有说过 GCD ----<barrier, group都是依赖的意思>
NSOperation之间可以设置依赖来保证执行顺序.
操作之间添加依赖
[operationB addDependency:operationA]
操作B依赖于A
不同队列之间也可以进行任务的依赖, 但是需要注意的是, 不要相互依赖