一、概念及定义
1、什么是闭包
闭包是自包含的函数代码块,可以在代码中被传递和使用。 Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的 lambdas 函数比较相似。
闭包可以捕获和存储其所在上下文中任意常量和变量的引用。 这就是所谓的闭合并包裹着这些常量和变量,俗称闭包。Swift 会为您管理在捕获过程中涉及到的所有内存操作。
在函数 章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一:
全局函数是一个有名字但不会捕获任何值的闭包
嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包
闭包表达式是一个利用轻量级语法所写的可以捕获其上下文中变量或常量值的匿名闭包
Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进行语法优化,主要优化如下:
利用上下文推断参数和返回值类型
隐式返回单表达式闭包,即单表达式闭包可以省略return关键字
参数名称缩写
尾随(Trailing)闭包语法
2、闭包的类型
2.1 闭包的形式有:
Swift中的闭包有很多优化的地方:
根据上下文推断参数和返回值类型
从单行表达式闭包中隐式返回(也就是闭包体只有一行代码,可以省略return)
可以使用简化参数名,如$0, $1(从0开始,表示第i个参数...)
提供了尾随闭包语法(Trailing closure syntax)
2.2 闭包表达式
闭包表达式是一种利用简洁语法构建内联闭包的方式。 闭包表达式提供了一些语法优化,使得撰写闭包变得简单明了。
格式:
1. 无参无返回值
{
//执行闭包表达式
}
2. 有参无返回值
{(参数列表) -> () in
}
3. 有参有返回值
{(参数列表) -> Int in
}
实例1:
let divide = {(val1:Int,val2:Int) -> Int in
return val1/val2
}
print(divide(700,50))
实例2:
sorted 方法
Swift 标准库提供了名为 sorted(by:) 的方法,会根据您提供的用于排序的闭包函数将已知类型数组中的值进行排序。
排序完成后,sorted(by:) 方法会返回一个与原数组大小相同,包含同类型元素且元素已正确排序的新数组。原数组不会被 sorted(by:) 方法修改。
sorted(by:)方法需要传入两个参数:
已知类型的数组
闭包函数,该闭包函数需要传入与数组元素类型相同的两个值,并返回一个布尔类型值来表明当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值前面,排序闭包函数需要返回 true,反之返回 false。
let names = ["AT", "AE", "D", "S", "BE"]
// 使用普通函数(或内嵌函数)提供排序功能,闭包函数类型需为(String, String) -> Bool。
func backwards(s1: String, s2: String) -> Bool {
return s1 > s2 //按字母降序排列,["S", "D", "BE", "AT", "AE"]
// return s1 < s2 //["AE", "AT", "BE", "D", "S"]
}
var reversed = names.sorted(by: backwards)
print(reversed)
2.3 尾随闭包
2.4 运算符闭包
实际上还有一种更简短的方式来撰写上面例子中的闭包表达式。
Swift 的String类型定义了关于大于号 (>) 的字符串实现,其作为一个函数接受两个String类型的参数并返回Bool类型的值。 而这正好与sort(_:)方法的第二个参数需要的函数类型相符合。 因此,您可以简单地传递一个大于号,Swift可以自动推断出您想使用大于号的字符串函数实现:
let names = ["AT", "AE", "D", "S", "BE"]
let reversed = names.sorted(by: <)
print(reversed)
2.5 值捕获
闭包可以在其定义的上下文中捕获常量或变量。
即使定义这些常量和变量的原域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。
Swift最简单的闭包形式是嵌套函数,也就是定义在其他函数的函数体内的函数。
嵌套函数可以捕获其外部函数所有的参数以及定义的常量和变量。
看这个例子:
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
//执行上面的闭包,值是累加的
let incrementByTen = makeIncrementor(forIncrement: 10)
print(incrementByTen()) //打印10
print(incrementByTen()) //打印20
print(incrementByTen()) 打印30
1.1闭包完整的定义
func <#name#>(<#parameters#>) -> <#return type#> {
<#function body#>
}
二、实例
1.定义闭包和执行闭包(无返回值)
//没有返回值,闭包必须是可选的
var compation:(()->())?
//执行
compation?()
执行时view.compation = {//执行回调代码}
//1.最简单的闭包
let b1 = {
print("swift 我爱你")
}
b1()// ()->()
//2.有参数有返回值的闭包,用in来与定义和代码实现分开
let b2 = {(x:Int)->Int in
return x
}
print(b2(100)) //(Int) -> Int
//3.带参数的闭包
let b3 = {(x:String) in
print(x)
}
b3("hello word swift")
//或写成
let b4 = {(x:String) ->() in
print(x)
}
b4("hello word")//(String)->()
2、监听按钮点击事件
//1.定义返回闭包
var btnClickBlock:(()->())?
//2.在A类view上添加按钮
let btn = UIButton(frame: CGRect(x: 15, y: 15, width: 80, height: 32));
btn.setTitle("按钮", for: .normal);
btn.backgroundColor = UIColor.blue;
//绑定事件
btn.addTarget(self, action: #selector(btnClick), for: .touchDown);
//添加
view.addSubview(btn);
//3.实现闭包
func btnClick() {
self.btnClickBlock?() //用?的好处是如果为空就不执行,用!如果没有值会崩溃
}
//4.在B类调用A类的这个闭包
A.btnClickBlock = {}
3.传入字典返回控制器
func setupViewController (dict:[String:String]) -> UIViewController{
return UIViewController()
}