闭包与Objective-C block | 青训营笔记

469 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的的第7天

闭包与Objective-C block | 青训营笔记

闭包

什么是闭包(closure)

闭包 ≈ 保存函数+函数所在环境的结构体

闭包中的环境

环境 = 约束变量(局部变量、传入的参数) + 自由变量(函数体外部定义的变量)

自由变量的确定

一般由语言设计者决定,也可由用户自行指定,如OC中不同类型的闭包

OC中的闭包

OC中闭包是由Block实现的

Block基础

Block本质:一种数据类型,类似函数指针,可以用来传回调函数

  1. 本质:内存变量
    1. 存储一段代码,可以有参数,可以有返回值
  2. 声明
    1. 指定参数返回值的个数和类型,只能存储
    2. 返回值类型 (^block变量名) (参数列表)
    3. void (^myBlock1)();
  3. 初始化
    1. Block变量名 = ^返回值类型(参数列表){代码;}
  4. 调用:
    1. Block变量名()
  5. 简写
    1. 代码段:
      1. 没有返回值可以省略void
        1. void (^myBlock1)() = ^(){};
      2. 没有参数可以省略()
        1. void (^myBlock1)() = ^{};
      3. 有返回值也可以省略返回值类型
    2. 声明:
      1. 可以只写类型,不写名称
  6. 使用typedef简写block:
    1. typedef 返回值类型 (^block类型名)(参数列表);
    2. eg 
      1. typedef void(^NewType)();
      2. NewType a = ^void{}; 
  7. Block访问外部变量
    1. Block代码块内部,可以取外部的局部变量和全局变量,但不能修改局部变量的值
    2. 可以修改的局部变量:用__block修饰局部变量
  8. Block作为函数的参数
    1. 回调函数
  9. Block作为函数的返回值

Block类型:

  1. 全局block
    1. NSGlobalBlock
    2. 保存在数据段
    3. 条件:定义在全局区/没有访问自动局部变量
  2. 栈block
    1. NSStackBlock
    2. 访问了自动局部变量
    3. 开启ARC时,有时会自动转为堆block
      1. Block作为函数返回值
      2. 将Block赋值给strong指针
      3. Block作为某些系统方法参数时
  3. 堆block
    1. NSMallocBlock
    2. 条件:通过调用stackblock的copy方法,生成的

block闭包的引用方式

  1. 值引用
    1. 基础类型:默认是值引用
    2. 对象:默认也是值引用,拷贝的是指针的地址
  2. 名称引用
    1. __block修饰符后,block内变为名称引用(地址)

    2. 对象属性,因为保存的是self,属性是在运行时通过发送消息获取的

block中的循环引用问题

  1. self持有block、block内持有self
    1. 通过__weak和__strong解决 

通过block实现链式调用

  1. 类实现方法,方法的返回值是block,block的返回值是类的实例(self),如Calculator.add
    1. 在block中进行操作,可以通过其他属性记录操作结果,如cal.result
    2. 初始化实例cal,cal.add是一个block,cal.add(2)对cal.result进行操作,返回cal,可以链式调用其他方法
  2. block实现异步操作
    1. GCD(Grand Central Dispatch)中dispatch_async/dispatch_after
  3. block本质还是一个对象
    1. 释放时机和普通变量一样