一.基础概念
闭包表达式:可以用func定义一个函数,也可以用闭包表达式来定义一个函数。闭包表达式不需要写外部名称,在外部使用时直接传入参数。
{
(参数列表) -> 返回值类型
in
函数体代码
}
尾随闭包:将闭包表达式作为参数的最后一个实参,用尾随闭包来增加函数可读性。将闭包写在小括号外: test(a:Int,b:Int){$0 + $1} 。如果闭包是唯一参数,则可以写作 test{$0 + $1},意义是调用test,并且传入这个闭包。忽略参数:不使用参数时候用_ 代替。闭包:(Closure),一个函数(一般指定义在函数内部的函数)和它捕获的变量\常量(捕获的是外层函数的局部变量\常量)组合在一起,称为闭包。捕获:如果是局部变量执行完之后生命周期就应该结束,但是如果闭包使用了外层函数的局部变量/常量,则会把这个值放入堆空间中,在后续的操作中不会用完就销毁。
typealias Fn = (Int) -> Int
func getFn() -> Fn{
var num = 0
func plus(_ i:Int) -> Int{
num += i
return num
}
return plus
}
var fn1 = getFn()
print(fn1(1))
print(fn1(2))
print(fn1(3))
print(fn1(4))
var fn2 = getFn()
print(fn2(5))
print(fn2(6))
print(fn2(7))
print(fn2(8))
闭包可以当作一个类的实例对象,内存在堆空间,捕获的局部变量\常量就是对象的成员,组成闭包的函数就是类内部定义的方法。把一个函数赋值给一个变量,内存中占16字节,前8位放直接调用的函数地址值,后8位放0。把一个闭包赋值给一个变量,前8字节放一个间接调用的函数地址,去向闭包中的函数,后8字节放一个堆空间的地址值,这个地址指向的是函数捕获的外部参数。在AT&T中,间接调用是call 后接一个寄存器地址,且地址前有一个*(星号)。闭包的捕获在调用闭包之前就已经把变量传到堆空间了,且是编译时需要明确闭包要被返回才是被捕获的,可以视作捕获是在return时候捕获的。为捕获变量申请堆空间的目的是保住这个变量的生命周期,当调用的变量如果是一个全局变量的话,那在程序运行中变量都存在数据段中,就不需要申请堆空间为期保命了,也就不会发生捕获的过程,严格来说调用一个全局变量就不是闭包了。捕获多个外部变量的时候,每个外部变量都有个属于自己独立的堆空间,都有自己的类型,引用计数,数据的空间。多个函数捕获同一个外部变量且只有一次函数调用的情况下,外部变量的堆空间是共享用的。自动闭包:@autoclosure,自动将传入值生成闭包表达式,只支持 ( )->T的函数形式。有无@autoclosure的同名函数构成函数重载。自动闭包的代码载空合运算中会延迟调用。
转载请注明原文地址:https://blackberry.8miu.com/read-45703.html