在Objective-C中,我们有block,在Swift中,我们有闭包,两者之间基本上一致,没有多大的区别,非要说起不同,也就是声明的语法有些差异,还有一些特性上的差异,下面让我们来看看.
1.前言
在讲闭包之前,我们来看看一个简单的例子:
let array = [1,2,3,5,10,20,30]
func backwards(s1: Int,s2: Int) -> Bool {
return s1 > s2
}
var reversed = array.sort(backwards)
print(reversed)
// 打印出来的结果:
// [30,20,10,5,3,2,1]
这是一个排序的例子,再想想,貌似没有了更好的简洁方式了吧,但这一切也只是在没有闭包之前,下面让我们来看看闭包的强大之处.
2.闭包表达式语法
reversed = array.sort( { (s1: Int,s2: Int) -> Bool in return s1 > s2 } )
这个就是闭包表达式的语法,完全不需要另外新建一个函数,就可以完成排序的操作.
3.根据上下文推断类型
reversed = array.sort({s1,s2 in return s1 > s2})
这也是一种闭包的写法,Swift中有一个特性就是会根据上下文去推断类型,而闭包也是可以如此的,所以我们可以直接这么写.
4.单表达式闭包隐式返回
reversed = array.sort({ s1,s2 in s1 > s2})
在闭包里,单行的闭包是可以不需要写return关键字的,默认就会返回.
5.参数名称缩写
reversed = array.sort( { $0 > $1 } )
这种写法也是闭包的表达式,不需要写参数名,就可以直接排序.
6.运算符函数
reversed = array.sort(>)
这种写法也是闭包的表达式,完全不需要任何参数,直接写明一个运算符就可以完成排序,但这种写法不太好,只能完成一些比较简单的排序.
7.尾随闭包
所谓的尾随闭包,就是自己声明一个闭包函数,在别的地方去调用.
func someFunctionThatTakesAClosure(closure: () -> Void) { // 闭包函数体 } // 写法一 someFunctionThatTakesAClosure({ // 闭包函数体 }) // 写法二 someFunctionThatTakesAClosure() { // 闭包函数体 }
8.map函数
在Swfit原生当中,有一个叫做map(_:)的函数,它也是一个闭包类型,下面让我们来看看.
let people = ["ZhangSan","LiSi","WangWu"]
let person = people.map { (var name) -> String in
print(name)
return name
}
map的用法和For-in有些类似,它会映射数组的元素,然后遍历,直到遍历到最后一个元素为止.
9.自动闭包和闭包的延迟操作
var numberArray = [1,4,6,7,8,9]
print(numberArray.count)
// 输出的结果为: 9
let customerProvider = { numberArray.removeAtIndex(0) }
print(numberArray.count)
// 输出的结果为: 9
print("Now serving \(customerProvider())!")
// 输出的结果为: Now serving 1!
print(numberArray.count)
// 输出的结果为: 8
这里的customerProvider就相当于我们自定义的一个闭包函数,虽然在闭包里,已经移除了一个元素,但该闭包并没有被调用,所以元素不会被移除.
10.闭包的其他知识
这里还有一个叫做逃逸闭包,和非逃逸闭包的概念:
所谓的逃逸闭包就是当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中逃逸,也就是说,在函数外部可访问,而非逃逸闭包就是只能在函数内部访问,一旦函数运行结束,闭包也就结束了.
这里有几个关键字: @noescape,@autoclosure,@autoclosure(escaping)
@noescape关键字来标注的闭包,就会变成非逃逸闭包,说明该闭包不能被函数外部所访问.
@autoclosure关键字来标注的参数,则会自动把参数转变成自动闭包,注意@autoclosure关键也是含有@noescape关键的特性,所以用@autoclosure来标注的闭包参数是不可以逃逸的.
@autoclosure(escaping)关键字来标注的参数,并且可逃逸.
var numberArray = [1,9]
func someFunctionWithNoescapeClosure(@noescape closure: () -> Void) { closure() } func serveCunstomer(@autoclosure customerProvider: () -> Int) { print("Now serving \(customerProvider())!") } var customerProviders: [() -> Int] = []
func collectCustomerProviders(@autoclosure(escaping) customerProvider: () -> Int) { customerProviders.append(customerProvider) }
这里有个例子,有兴趣的朋友可以自己去研究看看,如果想看更加详细的内容,可以去参考官方文档.
这次就讲到这里,下次继续