• 多线程之NSOperation小结


    一、NSOperation 抽象类

    • NSOperation 是一个"抽象类",不能直接使用。抽象类的用处是定义子类共有的属性和方法。
    • NSOperation 是基于 GCD 做的面向对象的封装。
    • 相比较 GCD 使用更加简单,并且提供了一些用 GCD 不是很好实现的功能。
    • 苹果公司推荐使用的并发技术。
    • 两个子类:
      • NSInvocationOperation (调用)
      • NSBlockOperation (块)

    相比NSInvocationOperation推荐使用NSBlockOperation,代码简单,同时由于闭包性使它没有传参问题。

    • NSOperationQueue 队列

    已经学习过的抽象类

    • UIGestureRecognizer
    • CAAnimation
    • CAPropertyAnimation

    二、 NSOperation 和 GCD 的核心概念

    • GCD的核心概念:将 任务(block) 添加到队列,并且指定执行任务的函数。
    • NSOperation 的核心概念:将 操作 添加到 队列。

    三、NSOperation 和 GCD的区别:

    GCD

    • 将任务(block)添加到队列(串行/并发/主队列),并且指定任务执行的函数(同步/异步)
    • GCD是底层的C语言构成的API
    • iOS 4.0 推出的,针对多核处理器的并发技术
    • 在队列中执行的是由 block 构成的任务,这是一个轻量级的数据结构
    • 要停止已经加入 queue 的 block 需要写复杂的代码
    • 需要通过 Barrier 或者同步任务设置任务之间的依赖关系
    • 只能设置队列的优先级
    • 高级功能:
      • 一次性 once
      • 延迟操作 after
      • 调度组

    NSOperation

    • 核心概念:把操作(异步)添加到队列。
    • OC 框架,更加面向对象,是对 GCD 的封装。
    • iOS 2.0 推出的,苹果推出 GCD 之后,对 NSOperation 的底层全部重写。
    • Operation作为一个对象,为我们提供了更多的选择。
    • 可以跨队列设置操作的依赖关系
    • 可以设置队列中每一个操作的优先级
    • 高级功能:
      • 最大操作并发数(GCD不好做)
      • 继续/暂停/全部取消
      • 跨队列设置操作的依赖关系

    四、代码实践

      1 //
      2 //  ViewController.m
      3 //  NSOperationTest
      4 //
      5 //  Created by mayl on 2018/1/5.
      6 //  Copyright © 2018年. All rights reserved.
      7 //
      8 
      9 #import "ViewController.h"
     10 
     11 @interface ViewController ()
     12 @property(nonatomic, strong) NSOperationQueue *gOpQueue;
     13 @end
     14 
     15 @implementation ViewController
     16 
     17 - (void)viewDidLoad {
     18     [super viewDidLoad];
     19     [self setUpUI];
     20     
     21 //    [self aysncCon];
     22     [self maxConCount];
     23 //    [self oftenUse];
     24 //    [self setUpDependence];
     25 //    [self waitUntilFinished];
     26 }
     27 
     28 - (void)setUpUI{
     29     
     30     //暂停,继续按钮
     31     UIButton *lBtn4Pause = [UIButton buttonWithType:UIButtonTypeCustom];
     32     [self.view addSubview:lBtn4Pause];
     33     
     34     lBtn4Pause.frame = CGRectMake(10, 100, 100, 50);
     35     [lBtn4Pause setTitle:@"挂起" forState:UIControlStateNormal];
     36     lBtn4Pause.titleLabel.numberOfLines = 0;
     37     [lBtn4Pause setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
     38     [lBtn4Pause addTarget:self action:@selector(pauseBtnDidClick:) forControlEvents:UIControlEventTouchUpInside];
     39     
     40     //取消所有任务按钮
     41     UIButton *lBtn4CancelAll = [UIButton buttonWithType:UIButtonTypeCustom];
     42     [self.view addSubview:lBtn4CancelAll];
     43     
     44     lBtn4CancelAll.frame = CGRectMake(150, 100, 100, 50);
     45     [lBtn4CancelAll setTitle:@"cancel all" forState:UIControlStateNormal];
     46     [lBtn4CancelAll setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
     47     [lBtn4CancelAll addTarget:self action:@selector(cancelAllBtnDidClick:) forControlEvents:UIControlEventTouchUpInside];
     48 }
     49 
     50 #pragma mark -  action
     51 
     52 /**
     53  队列挂起,当前"没有完成的操作",是包含在队列的操作数中的。
     54  队列挂起,不会影响已经执行操作的执行状态。
     55  队列一旦被挂起,再添加的操作不会被调度。
     56  */
     57 - (void)pauseBtnDidClick:(UIButton *)btn{
     58     NSLog(@"队列中操作数:%zd", self.gOpQueue.operationCount);
     59     if (0 == self.gOpQueue.operationCount) {
     60         NSLog(@"队列中无操作");
     61         return;
     62     }
     63     
     64     NSLog(@"3:%d", self.gOpQueue.isSuspended);
     65     self.gOpQueue.suspended = !self.gOpQueue.isSuspended;
     66     NSLog(@"4:%d", self.gOpQueue.isSuspended);
     67     if (self.gOpQueue.isSuspended) {
     68         NSLog(@"队列挂起");
     69         [btn setTitle:@"继续"
     70              forState:UIControlStateNormal];
     71     }else{
     72         NSLog(@"队列继续");
     73         [btn setTitle:@"挂起"
     74              forState:UIControlStateNormal];
     75     }
     76 }
     77 
     78 /**
     79  取消队列中所有的操作。
     80  不会取消正在执行中的操作。
     81  不会影响队列的挂起状态
     82  */
     83 - (void)cancelAllBtnDidClick:(UIButton *)btn{
     84     if (0 == self.gOpQueue.operationCount) {
     85         NSLog(@"队列中无操作");
     86         return;
     87     }
     88     
     89     NSLog(@"取消队列中所有操作,此方法不会改变队列挂起状态");
     90     [self.gOpQueue cancelAllOperations];
     91     
     92     NSLog(@"1:%d", self.gOpQueue.isSuspended);
     93     self.gOpQueue.suspended = !self.gOpQueue.isSuspended;
     94     NSLog(@"2:%d", self.gOpQueue.isSuspended);
     95 }
     96 
     97 /** 默认是:异步,并发 */
     98 - (void)aysncCon{
     99     NSOperationQueue *lQueue = [[NSOperationQueue alloc] init];
    100     for (int i = 0; i < 20; ++i) {
    101         [lQueue addOperationWithBlock:^{
    102             [NSThread sleepForTimeInterval:1];
    103             NSLog(@"%d,%@", i, [NSThread currentThread]);
    104         }];
    105     }
    106 }
    107 
    108 /** 最大并发数:The maximum number of queued operations that can execute at the same time.*/
    109 - (void)maxConCount{
    110     NSOperationQueue *lQueue = [[NSOperationQueue alloc] init];
    111     lQueue.maxConcurrentOperationCount = 2;
    112     for (int i = 0; i < 30; ++i) {
    113         [lQueue addOperationWithBlock:^{
    114             [NSThread sleepForTimeInterval:1];
    115             NSLog(@"%d,%@", i, [NSThread currentThread]);
    116         }];
    117     }
    118     
    119     self.gOpQueue = lQueue;
    120 }
    121 
    122 /** 常用:子线程耗时,主线程更新UI */
    123 - (void)oftenUse{
    124     NSOperationQueue *lQ = [[NSOperationQueue alloc] init];
    125     
    126     [lQ addOperationWithBlock:^{
    127         NSLog(@"耗时操作开始,%@", [NSThread currentThread]);
    128         [NSThread sleepForTimeInterval:3];
    129         NSLog(@"耗时操作结束");
    130         
    131         [[NSOperationQueue mainQueue] addOperationWithBlock:^{
    132             NSLog(@"主线程更新UI,%@",
    133                   [NSThread currentThread]);
    134         }];
    135         
    136     }];
    137 }
    138 
    139 /** 设置依赖 */
    140 - (void)setUpDependence{
    141     NSOperationQueue *lQ = [[NSOperationQueue alloc] init];
    142     
    143     [lQ addOperationWithBlock:^{
    144         [NSThread sleepForTimeInterval:1];
    145         NSLog(@"do something,%@",
    146               [NSThread currentThread]);
    147     }];
    148     
    149     NSBlockOperation *lOp1 = [NSBlockOperation blockOperationWithBlock:^{
    150         [NSThread sleepForTimeInterval:1];
    151         NSLog(@"1:登录,%@",
    152               [NSThread currentThread]);
    153     }];
    154     
    155     NSBlockOperation *lOp2 = [NSBlockOperation blockOperationWithBlock:^{
    156         [NSThread sleepForTimeInterval:1];
    157         NSLog(@"2:购买点券,%@",
    158               [NSThread currentThread]);
    159     }];
    160     
    161     NSBlockOperation *lOp3 = [NSBlockOperation blockOperationWithBlock:^{
    162         [NSThread sleepForTimeInterval:1];
    163         NSLog(@"3:使用点券,%@",
    164               [NSThread currentThread]);
    165     }];
    166     
    167     NSBlockOperation *lOp4 = [NSBlockOperation blockOperationWithBlock:^{
    168         [NSThread sleepForTimeInterval:1];
    169         NSLog(@"4:返回结果,%@",
    170               [NSThread currentThread]);
    171     }];
    172     
    173     [lOp2 addDependency:lOp1];
    174     [lOp3 addDependency:lOp2];
    175     [lOp4 addDependency:lOp3];
    176     
    177     //下面加的话会循环依赖,导致任何操作都无法进行,程序不会崩溃。
    178 //    [lOp1 addDependency:lOp4];
    179     
    180     [lQ addOperations:@[lOp4, lOp3] waitUntilFinished:NO];
    181     [lQ addOperations:@[lOp2, lOp1] waitUntilFinished:NO];
    182 }
    183 
    184 /**执行效果如下:
    185  2018-01-05 19:54:31.721539+0800 NSOperationTest[578:156322] come in
    186  2018-01-05 19:54:33.727691+0800 NSOperationTest[578:156342] 0:do others,<NSThread: 0x1c027f740>{number = 3, name = (null)}
    187  2018-01-05 19:54:34.731836+0800 NSOperationTest[578:156342] 1:登录,<NSThread: 0x1c027f740>{number = 3, name = (null)}
    188  2018-01-05 19:54:35.737375+0800 NSOperationTest[578:156342] 2:购买点券,<NSThread: 0x1c027f740>{number = 3, name = (null)}
    189  2018-01-05 19:54:36.742936+0800 NSOperationTest[578:156342] 3:使用点券,<NSThread: 0x1c027f740>{number = 3, name = (null)}
    190  2018-01-05 19:54:37.746491+0800 NSOperationTest[578:156342] 4:show Time,<NSThread: 0x1c027f740>{number = 3, name = (null)}
    191  2018-01-05 19:54:38.764408+0800 NSOperationTest[578:156341] 5:[lQ addOperations:@[lOp4, lOp3] waitUntilFinished:YES];实现了不设置依赖,且我需要最后执行,<NSThread: 0x1c04631c0>{number = 4, name = (null)}
    192  */
    193 - (void)waitUntilFinished{
    194     NSOperationQueue *lQ = [[NSOperationQueue alloc] init];
    195     
    196     NSLog(@"come in");
    197     NSBlockOperation *lOp0 = [NSBlockOperation blockOperationWithBlock:^{
    198         [NSThread sleepForTimeInterval:2];
    199         NSLog(@"0:do others,%@",
    200               [NSThread currentThread]);
    201     }];
    202     
    203     NSBlockOperation *lOp1 = [NSBlockOperation blockOperationWithBlock:^{
    204         [NSThread sleepForTimeInterval:1];
    205         NSLog(@"1:登录,%@",
    206               [NSThread currentThread]);
    207     }];
    208     
    209     NSBlockOperation *lOp2 = [NSBlockOperation blockOperationWithBlock:^{
    210         [NSThread sleepForTimeInterval:1];
    211         NSLog(@"2:购买点券,%@",
    212               [NSThread currentThread]);
    213     }];
    214     
    215     NSBlockOperation *lOp3 = [NSBlockOperation blockOperationWithBlock:^{
    216         [NSThread sleepForTimeInterval:1];
    217         NSLog(@"3:使用点券,%@",
    218               [NSThread currentThread]);
    219     }];
    220     
    221     NSBlockOperation *lOp4 = [NSBlockOperation blockOperationWithBlock:^{
    222         [NSThread sleepForTimeInterval:1];
    223         NSLog(@"4:show Time,%@",
    224               [NSThread currentThread]);
    225     }];
    226     
    227     NSBlockOperation *lOp5 = [NSBlockOperation blockOperationWithBlock:^{
    228         [NSThread sleepForTimeInterval:1];
    229         
    230         NSLog(@"5:[lQ addOperations:@[lOp4, lOp3] waitUntilFinished:YES];实现了不设置依赖,且我需要最后执行,%@",
    231               [NSThread currentThread]);
    232     }];
    233 
    234     [lOp2 addDependency:lOp1];
    235     [lOp3 addDependency:lOp2];
    236     [lOp4 addDependency:lOp3];
    237 
    238     //执行顺序跟在数组中的顺序无关
    239     //waitUntilFinished:If YES, the current thread is blocked until all of the specified operations finish executing. If NO, the operations are added to the queue and control returns immediately to the caller.(If YES,当前线程会被阻塞,直到数组中所有操作执行完毕。下局代码是直到lOp5执行完毕,才会执行后续操作)
    240     [lQ addOperations:@[lOp0] waitUntilFinished:YES];
    241     
    242     [lQ addOperations:@[lOp2, lOp1] waitUntilFinished:NO];
    243     [lQ addOperations:@[lOp4, lOp3] waitUntilFinished:YES];
    244     
    245     [lQ addOperation:lOp5];
    246 }
    247 
    248 @end
    学无止境,快乐编码。 没有一种不经过蔑视、忍受和奋斗就可以征服的命运。
  • 相关阅读:
    利用读写锁实现缓存系统
    POJ 1338 Ugly Numbers
    copy算法
    它们的定义iOS双击Home截图按键开关
    以正能量的点!!!
    该公路项目
    ArcSDE当关系查询ArcMap与REST查询结果不一致问题的解决
    【OpenCV新手教程第14】OpenCVHough变换:霍夫变换线,霍夫变换圆汇编
    为了树莓派IIraspberrypi安装emacs+ecb+cedet+session+color-theme+cscope+linum
    事件总线帧---Otto
  • 原文地址:https://www.cnblogs.com/Dast1/p/8204460.html
Copyright © 2020-2023  润新知