『iOS语法』闭包语法与实战
闭包这种语法,其实很多语言都在用,学过Android的朋友,一定发现,在gradle中用的很多。
iOS的闭包有一些自己语言的特性,这里一点点介绍一下。
写法
{(parameters) -> return type in
statements
}
闭包(Closures)是自包含的功能代码块,可以在代码中使用或者用来作为参数传值。
所有内容都写在{}中。
示例
var myClosure: () -> String = {
() -> String in
return "a"
}
这是定义了一个没有入参,返回值为String的闭包,然后将这个闭包赋值给myClosure,myClosure的类型为() -> String
这么解说就有点一目了然了吧。
这种没有入参的闭包还可以简写为:
var myClosure: () -> String = {
return "a"
}
那如果有参数的闭包呢?
var myClosure1: (String,String) -> Int = {
(val1: String, val2: String) -> Int in
return val1.count+val2.count
}
使用
对于有返回值的闭包,可以用来对某些变量赋值如:
var count1:Int = myClosure1("aa","bbb")
myClosure1已经之前声明了。
如果没有生命也可以这样使用:
var count2:Int = {
(val1: String, val2: String) -> Int in
return val1.count+val2.count
}("aa","bbb")
这样看着是不是有些别扭?为什么中括号后面还有跟一个()
如果觉得不好理解,可以这样想:
{
(val1: String, val2: String) -> Int in
return val1.count+val2.count
}
这个和myClosure1是可以互相替换的,myClosure1调用的时候为什么加(),这么说我想大家就容易明白了。
这种形式的闭包还可以简写为:
var count2:Int = {
return $0.count+$1.count
}("aa","bbb")
其中1表示第二个参数,以此类推。感觉是不是特别方便。
应用
在实际的开发过程中,其实很多地方都在用闭包,这里随便举几个例子。
回调
当需要使用异步回调的时候,可以传入一个闭包,如:
func test(callback: (String) ->Void) {
//do somethings
callback("result")
}
这个callback就是传入的回调闭包,我们可以在调用的时候传入:
test { (result) in
print(result)
}
其实还有一种写法,就是函数返回一个闭包的类型:
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
但是个人决定这种写法让程序的可读性变的很差,尽量避免这种写法。
数组方法
在数组中可以使用闭包完成很多事情(这里只是举个例子,除了数组,字典类型,同样提供了很多闭包入参的方法)
map
Map是数组的一个方法,他将传入的闭包的返回值生成一个数组:
let array = ["aaa","bbb","ccc","ddd","eee","fff"]
let array1 = array.map { (str) -> Bool in
return str.contains("aa")
}
let array2 = array.map {
return $0.contains("aa")
}
let array3 = array.map {
$0.contains("aa")
}
结果如下:
map 返回 [true, false, false, false, false, false]
filter
Filter虽然传入的闭包也是布尔的返回值,实际是利用这个返回值做一个筛选,也就是满足条件的(True)生成一个新的数组,如:
let array7 = array.filter { (str) -> Bool in
return str.count>=3
}
let array8 = array.filter {
$0.count >= 3
}
这两种写法效果是一样的。由于数组中所有的元素都满足这个条件,所以最终结果是:
map 返回 ["aaa", "bbb", "ccc", "ddd", "eee", "fff"]
我们可以再是一种方式:
let array9 = array.filter {
$0.contains("aa")
}
这个闭包跟上面例子中map传入的闭包一样,但是最终返回可是不一样的,map返回的是一个布尔数组,filter返回的是一个满足条件的数组:
map 返回 ["aaa"]
reduce
Reduce这个方法比较特殊,他的参数有两个,第一个为初始值,第二个为闭包,这个闭包的定义中有两个参数,一个就是初始值,一个就是遍历数组中的元素。最终返回的值,就是一个确定的值,而不再是一个数组,举个例子吧,我们需要遍历数组,统计数组中所有字符串长度的和。
let count11 = array.reduce(0) { (count, str) -> Int in
return count + str.count
}
let count22 = array.reduce(0) {
$0 + $1.count
}
上面两种写法效果是一样的。这里需要注意一个问题,如果一个方法有两个参数,最后一个是闭包,可以将闭包前面的参数写在括号中,如(0),闭包跟在最后
reduce(第一个参数) {
闭包
}
接着说上面的例子。
0表示初始化为0,也就是count的初始值为0,然后count每次都加元素的长度,遍历一遍,也就是最后总的长度了。
今天关于闭包就介绍这么多。闭包利用好可以使代码写起来更简单,但是也不能滥用,导致可读性变差。