多线程NSOperation

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];

控制台输出:


多线程NSOperation_第1张图片
Snip20150927_2.png

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())")
        }

多线程NSOperation_第2张图片
Snip20150928_2.png

***添加 queue.maxConcurrentOperationCount = 1
多线程NSOperation_第3张图片
Snip20150928_3.png

可以看出来, 线程并不是一样的. 所以最大并发数的理解, 应该是我上面指出的

2.队列的取消,暂停,和恢复
1>取消队列的所有操作
- (void)cancelAllOpertions
注意: 也可以调用NSOperation的-(void)cancel方法取消单个操作. (总感觉单个任务取消不掉)
2>暂停和恢复队列
- (void)setSuspended:(BOOL)b// YES 代表暂停队列,NO代表恢复队列
- (BOOL)isSuspended

操作依赖

首先依赖其他的线程中也有说过 GCD ----
NSOperation之间可以设置依赖来保证执行顺序.
操作之间添加依赖
[operationB addDependency:operationA] 操作B依赖于A
不同队列之间也可以进行任务的依赖, 但是需要注意的是, 不要相互依赖

你可能感兴趣的:(多线程NSOperation)