Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)

闭包表达式(Closure Expression)

可以通过func定义一个函数,也可以通过闭包表达式定义一个函数

  • func函数

  • 闭包定义函数

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第1张图片

闭包表达式调用可以直接省略参数名

闭包定义函数也可以写为:

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第2张图片

  • 闭包表达式的结构

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第3张图片


闭包表达式的简写

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第4张图片


尾随闭包

如果将一个很长的闭包表达式作为函数的最后一个实参,使用尾随闭包可以增强函数的可读性 

尾随闭包是一个被书写在函数调用括号外面(后面)的闭包表达式

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第5张图片

上面的函数使用闭包调用:

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第6张图片

如果闭包表达式是函数的唯一实参,而且使用了尾随闭包的语法,那就不需要在函数名后边写圆括号

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第7张图片

针对上面的函数,一般与闭包调用的对比:

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第8张图片


示例 - 数组的排序

数组排序的底层代码的定义:

由上面的底层代码可知,想要自定义一个数组排序,只需要传入一个有两个参数,返回值是Bool的函数

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第9张图片

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第10张图片

自定义排序方法的多种调用方式(闭包和简写):

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第11张图片


闭包(Closure)

 网上有各种关于闭包的定义,个人觉得比较严谨的定义是 :

  • 一个函数和它所捕获的变量\常量环境组合起来,称为闭包 
  • 一般指定义在函数内部的函数
  •  一般它捕获的是外层函数的局部变量\常量

定义了一个闭包:

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第12张图片

注:return plus前分配了一段堆空间,将num的值存储到了这个堆空间,调用plus访问的num实际上是堆空间的num, plus方法实际接收了两个参数:i和堆空间地址

使用反汇编看它实现的底层汇编代码:

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第13张图片

由图上红色框标注的汇编代码我们可以看出,在闭包里调用了swift_allocObject方法,我们可以理解为它在堆区申请了一块内存空间,用来存储它捕获的外层函数的局部变量或常量也就是num,这也就决定了num不会立刻销毁,由此我们可以看下它的计算结果:

func getFn() -> Fn {
    var num = 0
    func plus(_ i: Int) -> Int{
        num += 1
        return num
    }
    return plus
}

var fn = getFn()
print(fn(1))  //结果为1
print(fn(2))  //结果为3
print(fn(3))  //结果为6
print(fn(4))  //结果为10

可以看出计算结果是累加的,那就因为num存储在堆空间,没有销毁,上面的计算是对num的不断累加。

注意:如果num是全局变量,则不会在堆空间开辟内存。

注意:每调用一次getFn()都会申请一个新的内存空间,举例如下:

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第14张图片

由上面的计算可以看出,fn1和fn2是分开独立累加的,也就是fn1和fn2分别开辟了一块新内存,互不影响

反汇编代码如下:

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第15张图片

由上面的反汇编代码可以看出fn1和fn2前8个字节相同,因为都是指向同一个plus方法,但是后8个字节不同,因为分配的堆空间不同。

  •  可以把闭包想象成是一个类的实例对象
  •  内存在堆空间
  • 捕获的局部变量\常量就是对象的成员(存储属性) 
  • 组成闭包的函数就是类内部定义的方法

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第16张图片


闭包举例

  • 第一个例子:

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第17张图片

上面的闭包可以看成一个类:

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第18张图片

  • 第二个例子:

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第19张图片

上面的闭包同样可以看成一个类:

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第20张图片


参数注意

如果返回值类型是函数类型,那么参数的修饰要保持统一

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第21张图片


自动闭包

  •  @autoclosure 会自动将 20 封装成闭包 { 20 }
  •  @autoclosure 只支持 () -> T 格式的参数
  • @autoclosure 并非只支持最后1个参数
  •  空合并运算符 ?? 使用了 @autoclosure 技术
  •  有@autoclosure、无@autoclosure,构成了函数重载

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第22张图片

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第23张图片

Swift学习(八):闭包(闭包表达式,尾随闭包,闭包的定义,自动闭包)_第24张图片

为了避免与期望冲突,使用了@autoclosure的地方最好明确注释清楚:这个值会被推迟执行。

 

 

 

你可能感兴趣的:(移动开发iOS,移动开发,Swift,Swift,闭包,闭包表达式,尾随闭包,自动闭包)