美文网首页
NSOperation

NSOperation

作者: 彼岸的黑色曼陀罗 | 来源:发表于2016-09-26 16:52 被阅读0次

    NSOperation

    简介

    • 操作就是一个任务

    • 作用

      • 配合NSOperation和NSOperationQueue实现多线程编程
    • 实现多线程的具体步骤

      • 先将需要执行的操作封装到一个NSOperation对象中
      • 然后将NSOperation对象添加到NSOperationQueue中
      • 系统会自动将NSOperationQueue中的NSOperation取出来
      • 将取出的NSOperation封装的操作放到一条新的线程中执行
    • NSOperation的子类

      • NSOperation抽象类,并不具备封装操作的能力,必须使用它的子类
      • 使用NSOperation子类的方式
        • NSInvocationOperation
        • NSBlockOperation
        • 自定义子类继承NSOperation,实现内部相应的方法
      • NSInvocationOperation
        • 了解,本身不好用,开发中不经常用,swift里面没有InvocationOperation的API了

    封装操作的几种方式

    • 操作:一个op对象

    • 任务:方法里面的代码

    • NSInvocationOperation

      • 创建一个操作对象NSInvocationOperation alloc]initWithTarget:selector:object:
        • 第一个参数:目标对象self
        • 第二个参数:要调用的方法
        • 第三个参数:要调用方法需要接收的参数
      • 执行操作
        • start开始执行操作
      • 没有开子线程,在当前线程中串行执行
      • 必须要和队列结合起来使用,才能开线程
    • NSBlockOperation

      • 创建操作对象NSBlockOperation blockOperationWithBlock:^{}
      • 执行操作
        • start
      • 没有开子线程,在当前线程中串行执行
      • 特殊:对象方法addExcutionBlock追加任务,可能开子线程的
        • 注意点:NSBlockOperation在使用的时候,如果一个操作中任务的数量大于1,那么就会开启子线程和当前线程一起并发执行block中的代码(任务)

    操作队列的基本使用

    • NSInvocationOperation
      • 回顾GCD中的队列
        • 并发队列
          • 自己创建
          • 全局并发队列
        • 串行队列
          • 自己创建
          • 主队列
      • NSOperation队列
        • 主队列 mainQueue== GCD中串行队列中的主队列
          • 串行
          • 凡是在主队列中的任务都在主线程中执行
        • 非主队列 alloc]init
          • 默认情况下是并发队列
          • 可以设置为串行队列(最大并发数)
          • 可以开多条线程,并发执行任务
      • 基本使用
        • 创建一个非主队列alloc]init
        • 封装操作NSInvocationOperation alloc]initWithTarget:selector:object:
        • 添加操作到队列中addOperation
        • 为什么不调用start方法也能执行操作呢?因为addOperation内部会调用start方法】
    • NSBlockOperation
      • 创建队列alloc]init
      • 封装操作blockOperationWithBlock:
      • 添加操作到队列中 addOperation
      • 并发执行任务的
      • 追加任务 addExecutionBlock:^{}
      • 简便方法
        • queue addOperationWithBlock:^{}
        • 内部做了两件事情
          • 创建操作
          • 把操作添加到队列
        • 缺点:拿不到操作对象,无法设置操作

    NSOperation属性

    • 最大并发数(默认是-1)

      • 创建队列
      • 封装操作
      • 添加操作到队列中
      • 要求:按顺序执行任务,改为串行队列
        • 设置最大并发数(同一时间最多可以执行的任务的数量)maxConcurrentOperationCount = 1
        • 设置最大并发数的时候,要保证一个操作里面就有一个任务
          • 追加任务,最大并发数没有用了,因为追加任务大于1的时候,会自动开子线程,并发执行任务
        • 最大并发数不能设置为0,一般设置为5~6
        • 默认是-1,-1是指数量不受限制
    • suspended暂停任务

      • 创建队列
      • 封装操作
      • 设置最大并发数 = 1(便于观察suspend)
      • 添加操作到队列中
        • 注意点:开几条线程不是有操作数量决定的
        • suspended是BOOL类型
        • 定义一个队列属性
        • storyboard中添加控件
          • 开始
          • 暂停
            • setSuspended:YES
            • 没有立刻停住,操作是原子性的,block里的任务是一个整体,只要开始就停不下来,暂停是针对操作来说的
            • 暂停操作,只能暂停后面尚未执行的操作,对于当前处于执行状态的任务是没有影响的
          • 恢复
            • setSuspended:NO
          • 取消
            • cancelAllOperations队列里的所有的操作都会调用cancel方法
            • 取消之后,就不能恢复了
            • 取消操作只能取消后面尚未执行的操作,对于当前处于执行状态的任务是没有影响的

    自定义操作

    • 新建一个继承自NSOperation的类
    • 创建队列
    • 封装操作
      • 敲不出来alloc]initWithTarget: 和blockOperationWithBlock:
      • 只能用alloc]init
      • main方法里面封装操作,自定义的类里面重写main方法
    • 把操作添加到队列里面去
      • addOperation
    • 好处:
      • 能够提高代码的复用性,把代码放到main方法里
      • 信息隐蔽
    • 问题:
      • 不会马上取消
      • 产生原因
        • 三个for循环是一个整体,是同一个操作,是没有办法取消的
        • 拿到队列里的所有操作,调用cancel方法
      • 解决:每当执行完一个耗时操作之后,就检查当前的操作是否已经被取消,如果已经取消那么久结束任务
    if(self.isCancelled){
        return;
    }
    
    - 怎么达到点击取消,立刻就取消,把判断方法放到for循环里面,但是性能不好,不推荐使用
    

    操作队列中的依赖和监听(掌握)

    • 创建队列alloc]init
    • 添加三个操作
      • NSBlockOperation blockOperatinoWithBlock:
    • 怎么实现类似GCD栅栏函数,队列组功能?
      • 三个操作执行完毕后,执行任务4
      • 设置依赖
        • 任务4 addDependency 任务1
        • 任务4 addDependency 任务2
        • 任务4 addDependency 任务3
      • 可以设置多重依赖(按照4321的顺序执行)
        • 任务1 addDependency 任务2
        • 任务2 addDependency 任务3
        • 任务3 addDependency 任务4
      • 注意:不能设置循环依赖
      • 如果有多个队列,可以实现跨队列依赖
        • 任务5添加到第二个队列中
        • 可以让任务4依赖于任务5
      • 设置监听
        • .completionBlock = ^{}
    • 添加操作到队列
      • addOperation

    线程间通信

    • 下载图片在子线程,回到主线程刷新UI
    • 创建队列 alloc]init
    • 封装操作
      • NSBlockOperation blockOperationWithBlock:
      • 确定URL
      • 把图片的二进制数据下载到本地
      • 转换格式
    • 添加操作到队列
      • addOperation
      • 添加到队列之后,才会回过头来执行上面的block块
    • 回到主线程设置图片
      • 方式一:可以混合使用GCD
      • 方式二:
    NSOperationQueue mainQueue]addOperationWithBlock:^{
      self.imageV.image = image ;
        }    
    
    • 修改配置文件

    • 怎么使用操作队列下载两张图片合成一张图片?

    GCD和NSOperation对比

    • GCD是纯C语言的API,而操作队列则是OC的对象
    • 在GCD中任务用block块来表示,而block块是一个轻量级的数据结构;相反操作队列中的操作NSOperation对象则是一个更加重量级的OC对象
    • 开发中使用GCD还是NSOperation需要看具体的情况
      • 看个人喜好,一般而言,实现同一种功能,采用封装程度更高的NSOperation
      • 如果开发中,只是简单的开线程执行任务,可以使用GCD
      • 如果处理多个任务,并且有依赖关系,可以使用NSOperation

    NSOperation和NSOperationQueue的好处

    • NSOperationQueue可以方便的调用cancel方法来取消某一个操作,而GCD中的任务是无法被取消的(安排好任务之后就不管了)
    • NSOperation可以方便的指定操作间的依赖关系
    • NSOperation可以通过KVO提供对NSOperation对象的精细控制(如监听当前操作是否被取消或是否已经完成)
      • cancelld finished
      • 注册添加监听
        • download addObserver:options:旧值还是新值 context:
      • 调用方法observerValueForKeyPath:ofObject:change:context:
    • NSOperation可以方便的指定操作的优先级,操作优先级表示此操作与队列中的其他操作之间的优先关系,优先级高的操作先执行,优先级低的后执行
    • 通过自定义NSOperation的子类可以实现操作重用

    相关文章

      网友评论

          本文标题:NSOperation

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