多线程NSOperation

作者: Little_Dragon | 来源:发表于2015-09-28 10:39 被阅读54次

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

    控制台输出:


    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())")
            }
    
    
    Snip20150928_2.png
    ***添加queue.maxConcurrentOperationCount = 1
    Snip20150928_3.png
    可以看出来, 线程并不是一样的. 所以最大并发数的理解, 应该是我上面指出的

    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
    不同队列之间也可以进行任务的依赖, 但是需要注意的是, 不要相互依赖

    相关文章

      网友评论

        本文标题:多线程NSOperation

        本文链接:https://www.haomeiwen.com/subject/crewcttx.html