语法表达式
1 2 3 4 |
|
-
这里的参数(parameters),可以是in-out(输入输出参数),但不能设定默认值。如果是可变参数,必须放在最后一位,不然编译器报错。元组也可以作为参数或者返回值。
-
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
-
归纳
闭包类型是由参数类型和返回值类型决定,和函数是一样的。比如上面前三种写法的闭包的闭包类型就是(Int,Int)->(Int)
,后面的类型分别是()->Int
和()->Void
。分析下上面的代码:let calAdd:(add类型)
。这里的add类型就是闭包类型(Int,Int)->(Int)
。意思就是声明一个calAdd常量,其类型是个闭包类型。"="右边是一个代码块,即闭包的具体实现,相当于给左边的add常量赋值。兄弟们,是不是感觉很熟悉了,有点像OC中的block代码块。
起别名
-
也可以关键字“typealias”先声明一个闭包数据类型。类似于OC中的typedef起别名
1 2 3 4 5 6 7 8 9 |
|
尾随闭包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
值捕获
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
这里没有值捕获的原因是,没有去用一个常量或变量去引用函数,所以每次使用的函数都是新的。有点类似于OC中的匿名对象。
1 2 3 4 5 |
|
这里值捕获了,是因为函数被引用了,所以没有立即释放掉。所以函数体内的值可以被捕获
-
闭包形式
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
由上面的例子都可以证得,函数和闭包都是引用类型。
逃逸闭包
-
当一个闭包作为参数传到一个函数中,需要这个闭包在函数返回之后才被执行,我们就称该闭包从函数种逃逸。一般如果闭包在函数体内涉及到异步操作,但函数却是很快就会执行完毕并返回的,闭包必须要逃逸掉,以便异步操作的回调。
-
逃逸闭包一般用于异步函数的回调,比如网络请求成功的回调和失败的回调。语法:在函数的闭包行参前加关键字“@escaping”。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
自动闭包
1 2 3 4 5 6 7 8 9 10 11 12 13 |
5. 非逃逸闭包(Nonescaping Closures)一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中逃逸。可以在参数名之前标注 像刚才的数组的
你可能会问什么时候会出现逃逸闭包呢?举个例子:很多启动异步操作的函数接受一个闭包参数作为 非逃逸闭包和逃逸闭包讲的不是执行先后顺序吧,非逃逸是指你的闭包不能在函数外单独调用,只能在函数内部调用,函数调用完成后,那个闭包也就结束了。 下面举个逃逸闭包的例子: //声明一个存放函数的数组 var functionArray: [() -> Void] = [] //定义一个接收闭包参数的函数,如果定义非逃逸函数 func doSomething(@noescape paramClosure:() -> Void) 就会编译错误 func doSomething(paramClosure:@escaping () -> Void){ //把参数放入数组中,用于逃逸调用 functionArray.append(paramClosure) } //调用函数 doSomething(paramClosure: {print("Hello world")}) doSomething(paramClosure: {print("Hello LvesLi")}) //逃逸调用闭包 for closurePrama in functionArray { print("\(closurePrama)") } |