闭包是一个十分强大的功能,灵活多变,便于使用;实际上闭包是一种匿名的函数.
其类型和对应的函数类型保持一致.
使用闭包,我们可以动态的改变函数或方法中的代码,从而适应不同环境下的要求.
1.闭包的形式
- { (形参列表) ->返回值类型 in
- //其他代码
- }
对比函数的定义,如下
- func 函数名(参数列表) [ - > 返回值类型]
- {
- //函数体
- }
我们可以看到,闭包与函数的主要区别是 少了 func 函数名这一块;也就是说,函数与闭包的主要区别就是闭包是匿名的.
闭包示例:
- {
- (a:Int,b:Int)->Int in
- return a+b
- }
2.闭包的使用,闭包赋值给一个变量之后,该变量可以直接当函数使用
(1)定义一个闭包,功能是计算两个数之和,使用一个变量来接受该闭包.
- var plus =
- {
- (a:Int,b:Int)->Int in
- return a+b
- }
对于我们的写法系统则默认处理 plus为一个函数,见下图
(2)使用闭包,当做函数来使用闭包变量
- var c = plus(2,3)
- println(c)
当然我们也可以把 plus变量 用来接收其他的闭包
(3)闭包的外部形参名是没有作用的
和函数类似,闭包也可以使用外部形参名,但是闭包的外部形参名是没有任何作用的,我们使用闭包时,不能输入对于的外部形参名,否则会报错
- var plus =
- {
- (#a:Int,第二个参数 b:Int)->Int in
- return a+b
- }
对于上面的代码,我们需要使用如下的方式使用;不能传入外部形参名
- var c = plus(22,3)
- println(c)
- var c2 = plus(a:1,第二个参数 :3)
(4)定义完闭包之后直接调用该闭包
闭包还支持定义以后直接传入对应的参数来调用该闭包,调用闭包时需要使用括号.
如下面的代码,在定义完代码之后直接调用该闭包,结果返回给 plus变量
- var plus =
- {
- (a:Int,b:Int)->Int in
- return a+b
- }(2,3)
输出:
- 5
3.闭包的类型推断
闭包的类型,实际上一种函数类型;其类型可以根据用来接收闭包的变量的类型或者实参的类型来自动推断出 闭包对应的类型.
(1)闭包根据变量是 函数类型的 来推断其 参数类型,返回值类型
- var plus2:(Int,Int)->Int =
- {
- (a,b) in
- return a+b
- }
或者省略括号
- var plus2:(Int,Int)->Int =
- {
- a,b in
- return a+b
- }
此时的plus2是一个函数,所以我们使用如下方式调用闭包
- println(plus2(3,4))
(2)闭包根据传入的实参类型来自动推断闭包类型
- var app:Int =
- {
- a,b in
- return a+b
- }(111,222)
输出:对应的app的值
- println(app)
我们在定义闭包后直接调用闭包需要传入实参,闭包可以根据实参的类型来推断
其中 a,b参数的类型;返回值类型和 app的类型一致 推断出是 Int类型
4.闭包 省略 return 语句
当 闭包的内容只有一行,且该行语句是返回一个值,那么此时 return 可以省略
- var plus3:(Int,Int)->Int =
- {
- a,b in
- a+b
- }
如上面的闭包省略了 形参类型和 return ;
该闭包只有 一行语句且该语句就是闭包的返回值
5.省略形参名和 in 关键字
Swift不仅可以省略上述情况的一些东西,还允许省略 形参名 和 in;
Swift可以 通过 $0 ,$1 ...来引用第一个 ,第二个形参 ,第N个形参...
- var app3:Int =
- {
- return $0*$0
- }(111)
$0代表 $0
或者省略 return- var app2:Int =
- {
- $0*$1
- }(111,222)
$1代表222
原则是 闭包 可以根据 实参,或者 接收该闭包的变量的类型来自动推断类型6.尾随闭包
(1)闭包作为函数的一个参数
首先我们来定义一个 参数带有 函数类型的 函数
- func myFunc(#a:Int,#b:Int,#fun:(Int,Int)->Int)->Int
- {
- }
参数 fun是一个 函数类型的参数,我们可以传入一个函数 或者 闭包
完整定义
- func myFunc(#a:Int,#b:Int,#fun:(Int,Int)->Int)->Int
- {
- var c = fun(a,b)
- return c
- }
调用时传入一个 闭包
- var d = myFunc(a: 11, b: 22, fun: { return $0+$1})
或者:
- var d = myFunc(a: 11, b: 22, fun: { $0+$1})
fun闭包完全可以根据 myFunc形参类型来 省略 fun的 类型甚至 省略 return (因为只有一行语句)
(2)当函数的最后一个参数是函数类型时,可以使用尾随闭包,简化写法
可以看到步骤1 调用的方式 是 :
- myFunc(a:,b:,fun:{闭包体})
此种情况使用尾随闭包则可以写的更简洁
改为
- myFunc(a:,b:)
- {
- //闭包体
- }
- var cc = myFunc(a: 1, b: 2){$0+$1}
因为 a,b是属于 myFunc函数的 ,所以在闭包中 体中 并不知道 a,b这几个变量,只能使用 $0的形式
- 尾随闭包: 就是当函数的最后一个参数是函数类型时,调用函数 时,可传入一个闭包 ,该闭包可以放在 圆括号之外
7.捕获所对应的作用域的值
闭包可以访问 其所处的上下文(还有全局的)的变量和常量,称之为 捕获
- var dd = 2
- func myFunc(#a:Int,#b:Int,#fun:(Int,Int)->Int)->Int
- {
- var aa = 22, bb = 33
- var c = fun(dd,bb) //闭包可以访问 aa,bb
- return c
- }
如上代码 ,闭包 fun可以访问 全局变量 dd;
当然也可以访问 bb ,此称之为 捕获.
8.闭包的类型
Swift闭包 和 Oc的闭包类似,都是引用类型的;所以我们把复制 闭包变量时,实际上是复制的对应的指针; 复制的 副本 和 源 闭包变量指向同一变量
9.闭包的用途
闭包可以使用在 网络异步任务 , 界面传值 ,GCD ,数组排序,动画,组件封装 等地方;
灵活的使用闭包,可以让我们事半功倍