• iOS多线程之8.NSOPeration的其他用法


      本文主要对NSOPeration的一些重点属性和方法做出介绍,以便大家可以更好的使用NSOPeration。

    1.添加依赖

    - (void)addDependency:(NSOperation *)op;
      需求:同时下载两张图片,两张图片都下载完了,在合成成一张。这个例子我在iOS多线程之6.GCD的其他用法这篇文章中用过,当时是用GCD的group实现的。这次我们用NSOPeration实现。
    代码

    // 点击屏幕下载图片
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        
        __block UIImage *image1 = nil;
        // 下载图片1
        NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
            
            NSLog(@"下载第一张图片%@",[NSThread currentThread]);
            NSString *strURL1 = @"http://h.hiphotos.baidu.com/zhidao/pic/item/6d81800a19d8bc3ed69473cb848ba61ea8d34516.jpg";
            image1 = [self downloadImageWithURL:strURL1];
        }];
        __block UIImage *image2 = nil;
        // 下载图片2
        NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
            
            NSLog(@"下载第二张图片%@",[NSThread currentThread]);
            NSString *strURL2 = @"http://h.hiphotos.baidu.com/zhidao/pic/item/0eb30f2442a7d9334f268ca9a84bd11372f00159.jpg";
            image2 = [self downloadImageWithURL:strURL2];
        }];
        
        // 两张图片下载完 再合并图片
        NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
            
            NSLog(@"合并图片%@",[NSThread currentThread]);
            // 在主线程刷新UI
            dispatch_async(dispatch_get_main_queue(), ^{
                self.imageView1.image = image1;
                self.imageView2.image = image2;
                // 合并两张图片图片
                UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 100), NO, 0.0);
                [image1 drawInRect:CGRectMake(0, 0, 100, 100)];
                [image2 drawInRect:CGRectMake(100, 0, 100, 100)];
                self.imageView3.image = UIGraphicsGetImageFromCurrentImageContext();
                UIGraphicsEndImageContext();
    
            });
        }];
        
        // 添加依赖
        [operation3 addDependency:operation1];
        [operation3 addDependency:operation2];
        
        
        // 创建队列
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        // 把操作放队列中
        [queue addOperation:operation1];
        [queue addOperation:operation2];
        [queue addOperation:operation3];
    }
    
    - (UIImage *)downloadImageWithURL : (NSString *)strURL {
        NSURL *url = [NSURL URLWithString:strURL];
        return [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
    }
    

    日志

    2016-11-12 09:23:42.013 TTTTTTTTTT[2544:33281] 下载第二张图片<NSThread: 0x60000007ec40>{number = 4, name = (null)}
    2016-11-12 09:23:42.013 TTTTTTTTTT[2544:33282] 下载第一张图片<NSThread: 0x60000007cac0>{number = 3, name = (null)}
    2016-11-12 09:23:42.141 TTTTTTTTTT[2544:33309] 合并图片<NSThread: 0x60800007e700>{number = 6, name = (null)}
    

    效果:

    分析 :只有两张图片下载完,合并图片才有意义,所以operation3里面的操作必须等operation1和operation2里操作完成才能执行。
    [operation3 addDependency:operation1];
    operation3依赖于operation1,就是operation3等operation1执行完再执行。
    注意:依赖一定在把operation添加进queue之前添加,否则就没有意义了。
      既有添加依赖,就有移除依赖。
    - (void)removeDependency:(NSOperation *)op;

    2.设置operation的优先级

    @property NSOperationQueuePriority queuePriority;
       当把操作(operation)放入队列(queue)中的时候,是遵守先进先出原则。但是如果你设置了操作(operation)的优先级,那么优先级高的就可以先执行。NSOperationQueuePriority 是一个枚举,共有五个值。

    typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
    	NSOperationQueuePriorityVeryLow = -8L,// 优先级很低
    	NSOperationQueuePriorityLow = -4L,// 优先级低
    	NSOperationQueuePriorityNormal = 0,// 优先级正常
    	NSOperationQueuePriorityHigh = 4,// 优先级高
    	NSOperationQueuePriorityVeryHigh = 8// 优先级很高
    };
    

    e.g.:上面的例子,是第二张图片先下载的,是先执行operation2的,如果在把操作放在队列中之前设置operation1 的优先级为很高,就可以做到先下载第一张图片,先执行operation1。
    operation1.queuePriority = NSURLSessionTaskPriorityHigh;
    日志:

    2016-11-12 10:00:04.114 TTTTTTTTTT[4219:55622] 下载第一张图片<NSThread: 0x6080002613c0>{number = 3, name = (null)}
    2016-11-12 10:00:04.115 TTTTTTTTTT[4219:55611] 下载第二张图片<NSThread: 0x600000075340>{number = 4, name = (null)}
    2016-11-12 10:00:04.267 TTTTTTTTTT[4219:55644] 合并图片<NSThread: 0x600000264900>{number = 6, name = (null)}
    

    注意:优先级高的就一定会最先执行吗?不一定,这个例子比较简单,不能代表全部。优先级高只是提供了一个可能,至于会不会最先执行,还要看CPU的使用情况、操作的复杂程度和队列。同理,优先级低的也不一定会最后执行。

    3.操作的取消、执行、完成

    NSOperation的三个属性cancelled、executing、finished,分别就是取消,执行,完成。这三个属性都是只读的,我们通过这三个属性可以判断NSOperation的状态,是否取消了,是否正在执行,是否已经完成了。

    4.completionBlock

    如果你想在操作(operation)完成之后执行一些代码,可以写在这个block块里面。

    operation.completionBlock = ^{
            NSLog(@"我完成了");
        };
    

    注意:如果你把操作(operation)放入队列(queue)里面了,这行代码一定要放在添加之前,否则不执行。

    5队列的最大并发数

    @property NSInteger maxConcurrentOperationCount;
      这是NSOperationQueue的一个属性。由于NSOperationQueue里的操作都是并发的,所以我们可以设置同时并发多少个操作。如果不设置,系统默认。
    queue.maxConcurrentOperationCount = 3;
    注意:这个属性最好不要设置,系统默认就好。如果设置,最好不要超过5,最好是2-3。如果设置的太大, 会卡顿UI。因为CPU在多个线程之间切换,线程太多,什么时候才能轮到主线程刷新UI啊!。

    6.队列的暂停、恢复、取消

    1)暂停:
    [queue setSuspended:YES];
    2)恢复:
    [queue setSuspended:NO];
    3)判读队列的当前状态:
    @property (getter=isSuspended) BOOL suspended;
      当你把队列暂停时,队列里的操作就不执行了。当你滑动列表时,可以先把队列(队列里执行下载图片的操作,列表里的cell上有图片)暂停,不滑动时再恢复,增加APP的流畅性。
    4)取消所有操作
    - (void)cancelAllOperations;
      队列里的所有操作都不执行了。
      以上就是关于NSOperation的常用操作,用这些基本上就能够满足我们的需求。如果还满足不了怎么办,自定义NSOperation,下一篇文章讲自定义NSOperation。

  • 相关阅读:
    innerHTML获取标签内容
    images获取所有图片标签
    getElementsByTagName通过标签名获取元素对象集合
    getElementsByName通过标签的name属性来获取元素对象
    getElementsByClassName通过类名获取元素对象集合
    getElementById通过id找到对象
    tp3.2查询指定的字段
    流程控制语句if、else、elif、break、continue
    Python3基础知识之元组、集合、字典
    快速自定义输出格式
  • 原文地址:https://www.cnblogs.com/doujiangyoutiao/p/6058091.html
Copyright © 2020-2023  润新知