1、Closure
闭包在 Swift 中非常有用。通俗的解释就是一个 Int 类型里存储着一个整数,一个 String 类型包含着一串字符,同样,闭包是一个包含着函数的类型。有了闭包,你就可以处理很多在一些古老的语言中不能处理的事情。这是因为闭包使用的多样性,比如你可以将闭包赋值给一个变量,你也可以将闭包作为一个函数的参数,你甚至可以将闭包作为一个函数的返回值。它的强大之处可见一斑。在 Swift 的很多文档教材中都说函数是“一等公民”,起初我还不是很理解“一等公民”是什么意思,但当我理解了闭包以及它的强大功能后,我恍然大悟、茅塞顿开、醍醐灌顶。原来闭包的这些特性就是“一等公民”的特性啊!
闭包是功能性自包含模块,可以在代码中被传递和使用。一段程序代码通常由常量、变量和表达式组成,然后使用一对花括号“{}” 来表示闭合并包裹着这些代码,由这对花括号包裹着的代码块就是一个闭包。Swift 中的闭包与 C 和 Objective-C 中的 Block 以及其他一些编程语言中的 lambdas 比较相似。Block 和闭包的区别只是语法的不同而已,而且闭包的可读性比较强。
闭包是引用类型,无论你将函数/闭包赋值给一个常量还是变量,实际上都是在将常量/变量设置为对应函数/闭包的引用,这也意味着如果你将闭包赋值给了两个不同的常量/变量,两个值都会指向同一个闭包。
-
1)在 Swift 语言中有三种闭包形式:
- 全局函数:是一个有名字但不会捕获任何值的闭包。
- 嵌套函数:是一个有名字并可以捕获到其封闭函数域内的值的闭包。
- 匿名闭包:闭包表达式是一个利用轻量级语法所写的,可以捕获其上下文中变量或常量值。
-
2)函数形式:
func myConpare(s1:String, s2:String) -> Bool { return s1 > s2 } let namesArray:Array = ["Jill", "Tim", "Chris"] let names = namesArray.sort(myConpare)
-
3)一般形式:
{ (parameters参数) -> returnType返回类型 in statements }
可以使用常量、变量、inout、可变参数、元组类型作为闭包的参数,但不能在闭包参数中设置默认值,定义返回值和函数返回值的类型相同。
-
闭包表达式中的 in 关键字表示闭包的参数和返回值类型定义已经完成,这些参数和返回值都将在下面的闭包函数体中得到处理。
let namesArray:Array = ["Jill", "Tim", "Chris"] let names = namesArray.sort { (s1:String, s2:String) -> Bool in return s1 > s2 }
-
4)参数类型隐藏形式:
-
Swift 中有类型推断的特性,所以我们可以去掉参数类型。
let namesArray:Array = ["Jill", "Tim", "Chris"] let names = namesArray.sort { (s1, s2) -> Bool in return s1 > s2 }
-
-
5)返回值类型隐藏形式:
-
Swift 中有类型推断的特性,所以我们可以去掉返回值类型。
let namesArray:Array = ["Jill", "Tim", "Chris"] let names = namesArray.sort { (s1, s2) in return s1 > s2 }
-
-
6)return 隐藏形式:
-
单行表达式的闭包可以通过隐藏关键字 return 来隐式地将单行表达式的结果作为返回值。
let namesArray:Array = ["Jill", "Tim", "Chris"] let names = namesArray.sort { (s1, s2) in s1 > s2 }
-
-
7)参数名省略形式:
-
闭包的使用非常的灵活,我们可以省略闭包参数列表中的参数的参数类型定义,被省略的参数类型会通过闭包函数的类型进行推断。同时,我们也可以在闭包函数体中通过使用闭包的参数名简写功能,直接使用
$0、$1、$2
等名字就可以引用的闭包参数值。如果同时省略了参数名和参数类型,那么 in 关键字也必须被省略,此时闭包表达式完全由闭包函数体构成。let namesArray:Array = ["Jill", "Tim", "Chris"] let names = namesArray.sort { $0 > $1 }
-
-
8)trailing 闭包形式:
闭包可以做其他函数的参数,而且通常都是函数的最后一个参数。但是如果作为参数的这个闭包表达式非常长,那么很有可能会影响函数调用表达式的可读性,这个时候我们就应该使用 trailing 闭包。trailing 闭包和普通闭包的不同之处在于它是一个书写在函数参数括号之外(之后)的闭包表达式,函数会自动将其作为最后一个参数调用。
-
当函数有且仅有一个参数,并该参数是闭包时,不但可以将闭包写在 () 外,还可以省略 ()。Swift 2.2 中可以不管参数的个数完全省略 ()。
let namesArray:Array = ["Jill", "Tim", "Chris"] let names = namesArray.sort() { $0 > $1 }
-
9)闭包捕获:
-
闭包可以在其定义的上下文中捕获常量或变量,即使定义这些常量或变量的原作用域已经不存在,仍然可以在闭包函数体内引用和修改这些常量或变量,这种机制被称为闭包捕获。在 Swift 中闭包的最简单形式是嵌套函数。嵌套函数就可以捕获其父函数的参数以及定义的常量和变量,全局函数可以捕获其上下文中的常量或变量。
func increment(amount: Int) -> (() -> Int) { var total = 0 func incrementAmount() -> Int { // total 是外部函数体内的变量,这里是可以捕获到的 total += amount return total } // 返回的是一个嵌套函数(闭包) return incrementAmount } // 闭包是引用类型,所以 incrementByTen 声明为常量也可以修改 total let incrementByTen = increment(10) incrementByTen() // return 10,incrementByTen 是一个闭包 // 这里是没有改变对 increment 的引用,所以会保存之前的值 incrementByTen() // return 20 incrementByTen() // return 30 let incrementByOne = increment(1) incrementByOne() // return 1,incrementByOne 是一个闭包 incrementByOne() // return 2 incrementByTen() // return 40 incrementByOne() // return 3
-