54. Swift中闭包的语法:
{ ( parameters ) -> returnType in
statements
}
闭包的参数同样可以使常量、变量、inout类型的,但是不能提供默认值。参数列表和元组也可以在闭包中使用。
例如下面的闭包定义用来返回较大值:
{ (a : Int, b : Int) -> Int in return a >= b ? a : b }
当闭包的参数和返回值类型能够被推测出来时(大多数情况下都能被推测出来),可以省略掉参数类型和返回值,例如上面的例子可以简化为:
{ a, b in return a >= b ? a : b }
如果闭包中只有一条语句,则可以省略掉return关键字,例如上面的例子:
{ a, b in a >= b ? a : b }
Swift中还为我们提供了参数的快捷名称:$0,$1,$2…(数字表示参数的位置,第一个参数为$0),使用快捷名称来定义闭包,可以省略掉in关键字以及前面的参数定义,上面的例子可以继续优化为:
{ $0 >= $1 ? $0 : $1 }
55. 如果闭包作为一个函数的最后一个参数出现,在调用的时候可以将闭包写到函数参数的括号外面去,例如我们用闭包来定义一个冒泡排序:
func sort(nums : Int[], comp : (Int, Int) -> Bool, swap :(inout Int, inout Int) -> ()) -> Int[] {
var count = countElements(nums) - 1
for var i = 0; i < count; i++ {
for var j = 0; j< count - i; j++ {
if comp(nums[j], nums[j+1]) {
swap(&nums[j], &nums[j+1])
}
}
}
return nums
}
var arr = [1, 6, 8, 2, 7, 0, 5, 3, 9, 4, 6, 2]
println(sort(arr, >) { (inout a : Int, inout b : Int)-> () in
if a >= b {
var temp = a
a = b
b = temp
}
})
如果函数唯一的一个参数是闭包表达式,则调用的时候可以不写省略掉圆括号“()”。
56. 闭包能够记录包含闭包的上下文中定义的变量和常量,并且能够在闭包代码块中修改和访问它们(甚至当这些变量和常量随着作用域的更改不再有效)。例如:
func makeIncrementor(amount : Int) -> ()->Int {
var total = 0
var incrementor = {()-> Int in
total += amount
return total
}
return incrementor
}
var inc = makeIncrementor(10)
println(inc()) //输出10
println(inc()) //输出20
println(inc()) //输出30
这里由于创建出来的incrementor函数不会修改amount参数,所以新创建出来的incrementor方法会拷贝一个amount的副本,原来的amount会随着makeIncrementor函数的结束而被释放,但是incrementor函数中确实修改了total变量的值,因此它会保留total变量的一个引用,从而保证total不会随着makeIncrementor函数的结束而被释放掉。
57. Swift中函数和闭包是引用类型。
58. Swift中的枚举类型定义:
enum Direction {
case North
case South
case East
case West
}
也可以在一个case中写多个枚举成员:
enum Direction {
case North, South, East, West
}
59. 对于枚举类型,可以在定义中允许枚举值保存附加信息,例如:
enum Product {
case Product1(Float,Int) //Discount, Price
case Product2(Float,String) //Discount, Gifts
}
var product1 = Product.Product1(0.8, 120)
var product2 = Product.Product2(0.75, "Product3")
在Switch语句中可以使用变量中保存的信息:
switch product {
case Product.Product1(let discount, let price):
println(“Product1 with a discount of \(discount), and theprice is \(price)”)
case Product.Product2(let discount, let gift):
println(“Product2 with a discount of\(discount), and with \(gift) as a gift”)
}
60. 枚举类的原生数据(raw value)可以是字符串、字符、整型或者浮点型,在定义的时候在枚举名后面加上冒号和类型来声明,如果原声数据类型是整型,那么对于没有指定的枚举成员会自动递增。例如:
enum ASCIIControlChar : Character {
case Tab = “\t”
case LineFeed = “\n”
case ReturnToLineStart = “\r”
}
注意Swift中字符也是使用双引号来定义的。
enum CompareResult : Int {
case LessThan = 0
caseEqual //自动增加为1
caseGreaterThan //自动增加为2
}
使用toRaw()方法来将枚举值转换为对应的原声数据:
var cmpResult = CompareResult.Equal.toRaw()
使用fromRaw()方法来将原生数据转换为枚举值:
var cmpResult = CompareResult.fromRaw(1)
fromRaw方法返回一个可选类型,当转换失败的时候,返回nil。
61. Swift中的结构体中也可以定义方法以及构造函数(或者说初始化函数),但是不能定义析构函数。结构体没有深浅拷贝之说,在赋值的时候都是完全拷贝出一个新的结构体赋给目标变量,类在赋值的时候,如果不使用深拷贝,则只传递引用,结构体无继承。
62. Swift中的结构体在定义好之后,默认会生成一个初始化方法,这个初始化方法需要指定参数名来调用,且参数的顺序要喝结构体中的声明顺序一致:
struct Student {
var name : String
var age : Int
var score : Int
}
var s1 = Student(name : "Someone", age : 15, score: 95)
对于Swift中的类,如果不指定初始化函数的话,不会自动生成类似上面的初始化方法。
63. 对于Swift中的结构体和类,如果在定义的时候所有的属性都给出了初始值,则Swift会自动为其创建一个不含参数的初始化方法,例如:
struct Student {
var name : String = ""
var age : Int = 0
var score : Int = 0
}
var s = Student()
如果一个以上的属性没有初始值,则不会生成不含参的构造方法。
64. Swift中的Dictionary在拷贝或者传参的时候与结构体相同,会深拷贝一份完全相同的Dictionary对象。如果Dictionary的键值中有引用类型,则会拷贝出一个引用来,如果键值都是值类型,则拷贝相同的值。
65. Swift中的Array在拷贝或者传参的时候,不会立即复制一份完全相同的Array对象,而是先临时共享公共的内容,当程序将要修改其中某个Array的元素的时候,另一个Array也同样被修改了(或者说因为两个Array指向同一个共享的内容,所以修改一个也会影响另一个)。只有当Array的大小(元素数量)发生变化的时候,才会完成内容的拷贝,两个Array此时才会各自拥有自己的内容,拷贝的效果和Dictionary对象相同:值类型完全拷贝,引用类型拷贝引用值。例如:
var array1 = [1, 2, 3, 4]
var array2 = array1
array1[3] = 5
println(array2)
这个例子array2输出1,2,3,5,也就是修改array1的第四个元素同时也影响了array2,即由于修改没有改变数组的大小,两个数组共享相同的内容。接着看下面的例子:
var array1 = [1, 2, 3, 4]
var array2 = array1
array1 += 5
array1[3] = 5
println(array2)
输出结果为1,2,3,4,因为在array1中加入元素(“5”)的时候,array1从共享的内容中拷贝出了一份内容,而array2仍然指向原来共享的内容(此时已经不共享了),因此没有受到array1[3]=5这句的影响。
66. 对于Array来说,如果希望数组在复制的时候,不共享共同的内容,除了刻意地修改其大小外,还可以调用unshare()方法(注意:常量数组不能调用unshare()方法),例如:
var array1 = [1, 2, 3]
var array2 = array1
array1.unshare() //也可以调用array2.unshare()
array1[0] = 5
println(array2) //输出1, 2, 3
此外,还可以使用copy方法来强制完成拷贝:
var array1 = [1, 2, 3]
var array2 = array1.copy()
array1[0] = 5
println(array2) //输出1, 2, 3
unshared和copy比起来要是一个更好的选择,unshare方法只会在需要的时候进行拷贝,而copy方法会在调用的时候立即完成拷贝。