英文版PDF下载地址http://download.csdn.net/detail/tsingheng/7480427
Swift提供数组和字典两种集合类型,用来存储许多值的情况。数组有序的存储一组相同类型的值。字典也存储一组相同类型的值但是是无序的,字典中存储的值可以通过一个唯一的标识(也就是Key)来查找。
在Swift中,数组和字典总是清楚自己能存储的值的类型和key的类型。也就是说你不会错误的把其他不对应的类型存进数组或者字典。所以你也能确定从数组或者字典中取出来的值的类型肯定也不会错了。Swift使用显式类型集合来保证你的代码总是能清除的知道数组和字典中存储的值的类型,确保你在开发阶段就能发现所有类型错误。
NOTE 当你将数组赋值给其他变量或者常量,或者传递给函数或方法的时候,数组的行为跟其他类型是不太一样的,更多信息在可变集合与集合类型赋值与拷贝里面介绍。
1.数组
数组可以以有序状态存储同一类型的多个值。同一个值也可以在同一个数组的不同位置多次出现。
Swift数组能存储的值的类型是特定的。他跟OC的NSArray或者NSMutableArray类不一样,这两个类可以存储任何对象,不用说明他们返回的值是什么类型。但是在Swift里,特定的数组能存储的值的类型必须要说明清楚,要么是通过类型标注,要么通过类型推断,而且不需要一定是class类型。如果你创建一个Int值的数组,你就不能向这个数组里面存储除了Int类型意外的任何值。Swift数组总是类型安全的,总是清除数组可以存储什么类型。
数组类型简写
Swift数组的类型完整形式是Array<SomeType>这样的,SomeType就是数组允许存储的类型。你也可以使用简写形式SomeType[]。虽然说两种形式功能是相同的,但是更推荐使用简写形式,这本手册也将采取简写形式。
数组字面值
你可以使用数组字面值来初始化数组,这是将一个或多个值定义成数组的简写方式。数组字面值形式是一组值以逗号分隔,外面再加上中括号。比如[value 1, value 2, value 3]。
下面例子创建了一个数组shoppingList来存数字符串
var shoppingList: String[] = ["Eggs", "Milk"]
// shoppingList has been initialized with two initial items
变量shoppingList被声明为“字符串值的数组”,写作String[]。因为这个数组被声明是字符串类型,所以这个数组就只能存储字符串。这里shoppingList数组被使用两个字符串值的数组字面值来初始化。
NOTE 注意上面数组shoppingList是被声明为变量而不是常量,因为后面例子中还要向这个数组中添加更多地元素。
在这个例子中数组字面值只包含了两个字符串,正好匹配shoppingList的声明(只能存储字符串类型的数组),所以使用字面值赋值被允许用来初始化数组shoppingList。
因为Swift有类型推断机制,所以当你使用只包含一种类型的数组字面值来初始化数组的时候是可以不用指明数组类型的。上面shoppingList的声明可以这条语句代替 var shoppingList = ["Eggs", "Milk"] 因为用来初始化的数组字面值包含的类型都是相同的,所以Swift可以推断出Sring[]就是用来声明shoppingList的正确类型。
获取和修改数组
你可以通过数组的方法或者属性或者使用下标语法来获取和修改数组。
要想知道数组拥有几个元素,可以通过数组的只读属性count
println("The shopping list contains \(shoppingList.count) items.")
// prints "The shopping list contains 2 items.
使用属性isEmpty可以作判断count属性是否为0
if shoppingList.isEmpty {
println("The shopping list is empty.")
} else {
println("The shopping list is not empty.")
}
// prints "The shopping list is not empty."
你可以通过调用append方法来向数组的末尾添加元素
shoppingList.append("Flour")
// shoppingList now contains 3 items, and someone is making pancakes
或者也可以使用+=操作符来向数组末尾添加元素:
shoppingList += "Baking Powder"
// shoppingList now contains 4 items
你还可以使用+=符号来向数组中添加一个类型匹配的数组:
shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
// shoppingList now contains 7 items
如果要获取数组中的值就用下标语法,在数组名后面加上中括号,中括号里面写你想要获取的值的序号:
var firstItem = shoppingList[0]
// firstItem is equal to "Eggs”
注意数组中第一个元素的下标是0而不是1。Swift中的数组下标都是从0开始的。
你可以使用下标语法来修改已经存在数组中的值:
shoppingList[0] = "Six eggs"
// the first item in the list is now equal to "Six eggs" rather than "Eggs”
你还可以使用下标语法一次性修改多个值,即使要替换的数组长度跟使用的下标范围长度不一样都行。下面例子把"chocolate Spread",”Cheese“,”Butter“替换成"Bananas"和"Apples":
shoppingList[4...6] = ["Bananas", "Apples"]
// shoppingList now contains 6 items
NOTE 不可以使用下标语法来向数组末尾添加元素。如果你使用下标语法的时候使用了超出数组现有下标范围的数值,将会发生运行时错误。不过你可以在使用下标的时候先通过比较该下标是否不大于数组的count属性来检测是否越界。除了count是0得情况,数组可以使用的最大下标总是count-1。
如果要再数组特定位置插入元素,需要调用数组的方法insert(atIndex:):
shoppingList.insert("Maple Syrup", atIndex: 0)
// shoppingList now contains 7 items
// "Maple Syrup" is now the first item in the list”
上面例子调用以后将会在数组的最前面也就是下标为0加入元素"Maple Syrup"。
类似的,你可以使用removeAtIndex方法来移除数组中的元素。这个方法移除指定的元素,并且返回被移除的元素(虽然你可以忽略这个返回的元素,但是他还是会返回):
let mapleSyrup = shoppingList.removeAtIndex(0)
// the item that was at index 0 has just been removed
// shoppingList now contains 6 items, and no Maple Syrup
// the mapleSyrup constant is now equal to the removed "Maple Syrup" string”
数组中任何元素被移除后空隙都会被填充,所以上面例子移除第0个以后,第0个马上就会被"Six eggs"替换:
firstItem = shoppingList[0]
// firstItem is now equal to "Six eggs”
如果你像移除数组中最后一个元素,使用removeLast方法而不是removeAtIndex方法,这样可以不用再使用count属性。和removeAtIndex方法一样,removeLast也返回被移除的元素:
let apples = shoppingList.removeLast()
// the last item in the array has just been removed
// shoppingList now contains 5 items, and no cheese
// the apples constant is now equal to the removed "Apples" string”
遍历数组
你可以是用for-in循环来遍历数组中的元素
for item in shoppingList {
println(item)
}
// Six eggs
// Milk
// Flour
// Baking Powder
// Bananas
如果你又想获取元素的值又想获取元素的下标,那就使用全局函数enumerate来遍历数组。enumerate函数为每一个元素返回一个包含了下标和元素值的元组。你可以解析元素赋值给临时常亮或者变量作为遍历的一部分:
for (index, value) in enumerate(shoppingList) {
println("Item \(index + 1): \(value)")
}
// Item 1: Six eggs
// Item 2: Milk
// Item 3: Flour
// Item 4: Baking Powder
// Item 5: Bananas
创建和初始化数组
你可以使用初始化语法来创建特定类型的空数组(不设置任何初始值)。
var someInts = Int[]()
println("someInts is of type Int[] with \(someInts.count) items.")
// prints "someInts is of type Int[] with 0 items.”
注意数组someInts的类型被是Int[],因为他被设置为Int[]初始化的结果。
或者如果上下文中已经说明了类型信息,比如函数参数或者一个已经定义过类型的变量或常量,那你就可以使用空得数组字面量[]还创建空数组。
someInts.append(3)
// someInts now contains 1 value of type Int
someInts = []
// someInts is now an empty array, but is still of type Int[]
Swfit的数组类型还提供一个初始化器来创建特定长度,各个元素都被指定为默认值的数组。你需要传递给初始化器需要添加的元素数量和一个初始值:
var threeDoubles = Double[](count: 3, repeatedValue: 0.0)
// threeDoubles is of type Double[], and equals [0.0, 0.0, 0.0]
因为有类型推断,所以在使用这个初始化器的时候是不需要指定数组类型的。因为数组类型从默认值可以推断出来:
var anotherThreeDoubles = Array(count: 3, repeatedValue: 2.5)
// anotherThreeDoubles is inferred as Double[], and equals [2.5, 2.5, 2.5]
最后,你可以通过两个现有的类型匹配的数组相加来创建新的数组。新数组的类型将从相加的两个数组中推断出来:
var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles is inferred as Double[], and equals [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]
字典是一个可以存储同一类型的多个值的容器。各个值跟一个唯一的key关联,key在字典中是值的唯一标识。跟数组中的元素不同的是,字典中的元素没有特定的顺序。当你需要使用元素的标识来查找的时候可以使用字典,在现实世界中我们使用字典根据单词来查找定义。
Swift字典也是明确知道自己可以存储的key可value的类型。字典和OC的NSDictionary以及NSMutableDictionary不同,NSDictionary和NSMutableDictionary可以使用任何对象作为key和value,而且不需要提供这些对象的任何类型信息。在Swift中,一个特定的字典可以存储的key和value的类型总是要指明的,要么通过类型标注,要么通过类型推断。
Swift的字典类型写作Dictionary<KeyType, ValueType>,KeyType是可以用作字典Key的类型,ValueType是字典可以存储的value的类型。
唯一的限制是KeyType必须是hashable,也就是说他必须要提供一个另自己唯一表示的方式。Swift的所有基础类型(比如String,Int,Double和Bool)默认都是hashable,所以这些类型都可以作为字典的key。没有关联值的枚举成员默认也是hashable
字典字面值
你可以使用字典字面值来初始化字典,字典字面值跟前面的数组字面值语法类似。字典字面值是将一个或多个key-value对写成字典集合的简便方式。
一个key-value对是一个key与一个value的绑定。在字典字面值中,各个key-value用逗号隔开并被中括号包围,key与value用冒号隔开:
[key 1: value 1, key 2: value 2, key 3: value 3]
下面例子创建了一个字典来存储国际机场的名称:
var airports: Dictionary<String, String> = ["TYO": "Tokyo", "DUB": "Dublin"]
字典airport被声明为Dictionary<String, String>类型,意思是”key类型为String,value类型也为String的字典“
NOTE 字典airports被声明为变量而不是常量,因为后面例子中还会向其中添加更多元素。
字典airports被使用包含两个key-value对的字典字面值初始化。第一对key是”TYO",value是”Tokyo“,第二对key是"DUB",value是”Dublin“。
这个字典字面值包含两个字符串:字符串对。正好匹配变量airports声明的类型,所以使用字典字面值赋值被允许用来初始化字典airports。
也数组一样,如果你使用key和value保持一致的字典字面值来初始化字典的时候也不必要再写出字典的类型。airports的初始化可以使用下面的简写方式:
var airports = ["TYO": "Tokyo", "DUB": "Dublin"]
因为字典字面值中各个元素的key类型是一样的,各个元素的value类型也是一样的,所以swift可以推断出来Dictionary<String, String>就是用来初始化字典airport的正确类型。
获取和修改字典
你可以通过字典的属性或者方法或者下标语法来获取和修改字典。和数组一样,你可以使用count属性来查看字典中的元素个数。
println("The dictionary of airports contains \(airports.count) items.")
// prints "The dictionary of airports contains 2 items.
你可以使用下标语法想字典中添加新元素。使用新的Key作为下标值,并且使用心得value来赋值:
airports["LHR"] = "London"
// the airports dictionary now contains 3 items
你也可以使用下标语法来修改特定Key关联的值:
airports["LHR"] = "London Heathrow"
// the value for "LHR" has been changed to "London Heathrow
还可以使用字典的updateValue(forKey:)方法来设置或者更新特定key对应的值。想上面的下标例子一样,如果对应的value不存在,就添加一条记录,如果存在就更新记录。不过和下标语法不一样的是,updateValue(forKey:)方法返回的是旧的值。这样你可以检查更新有没有生效。
updateValue(forKey:)方法返回字典value类型的可选值。比如上面存储字符串值的字典,该方法返回字符串可选值。如果更新前value存在,返回的可选值当中存储原来的value,如果不存在,返回的就是nil。
if let oldValue = airports.updateValue("Dublin International", forKey: "DUB") {
println("The old value for DUB was \(oldValue).")
}
// prints "The old value for DUB was Dublin.”
你也可以使用下标语法来查询子字典中特定key对应的值。因为允许使用不存在的key,所以使用字典下标返回的时一个可选值。如果字典包含key所对应的value,返回的就是这个value,如果不包含,返回的就是nil。
if let airportName = airports["DUB"] {
println("The name of the airport is \(airportName).")
} else {
println("That airport is not in the airports dictionary.")
}
// prints "The name of the airport is Dublin International.”
你可以使用下标语法给特定key的值赋值为nil来从字典中删除这个元素。
airports["APL"] = "Apple International"
// "Apple International" is not the real airport for APL, so delete it
airports["APL"] = nil
// APL has now been removed from the dictionary
或者还可以使用removeValueForKey方法来移除元素。如果存在元素,就移除然后返回该元素,如果不存在就直接返回nil。
if let removedValue = airports.removeValueForKey("DUB") {
println("The removed airport's name is \(removedValue).")
} else {
println("The airports dictionary does not contain a value for DUB.")
}
// prints "The removed airport's name is Dublin International.”
遍历字典
你可以使用for-in循环来遍历字典。字典哥哥元素返回一个(key, value)的元组,你可以解析元组成员到临时变量或者常量中:
for (airportCode, airportName) in airports {
println("\(airportCode): \(airportName)")
}
// TYO: Tokyo
// LHR: London Heathrow
你还可以通过字典的额keys属性和values属性来获取字典的key集合或者value集合:
for airportCode in airports.keys {
println("Airport code: \(airportCode)")
}
// Airport code: TYO
// Airport code: LHR
for airportName in airports.values {
println("Airport name: \(airportName)")
}
// Airport name: Tokyo
// Airport name: London Heathrow
如果你需要通过一个数组实例来使用字典的keys或者values,就用属性keys或者values来初始化数组:
let airportCodes = Array(airports.keys)
// airportCodes is ["TYO", "LHR"]
let airportNames = Array(airports.values)
// airportNames is ["Tokyo", "London Heathrow"]
NOTE Swift的字典是无序集合。当遍历字典的时候,字典中keys,values以及key-value对的获取顺序都是不固定的。
创建空字典
和数组一样,你可以使用初始化语法来创建特定类型的空字典:
var namesOfIntegers = Dictionary<Int, String>()
// namesOfIntegers is an empty Dictionary<Int, String>
这个例子创建了Int,String类型的字典来保存整数的名称。key的类型是Int,value的类型是String。
如果上下文已经提供了类型信息,就可以直接使用空字典字面值来创建空字典,空字典字面值写作[:]:
namesOfIntegers[16] = "sixteen"
// namesOfIntegers now contains 1 key-value pair
namesOfIntegers = [:]
// namesOfIntegers is once again an empty dictionary of type Int, String
NOTE Swift的数组和字典类型是泛型集合的实现。更多泛型和集合信息请查阅泛型。
3.可修改集合
数组和字典将多个元素存储到一个集合中。如果你创建了一个数组或者字典,并且赋值给一个变量,那么创建的集合就是可以修改的。也就是说你可以在集合创建以后添加更多地元素或者移除已有元素来改变集合的长度。反过来如果你把数组或者字典赋值给常量,那么这个数组或者字典就是不可变得,长度也不能改变。
对于字典来说,不可变星还以为这你不恩给你替换已有的key对应的value。不可变的字典内容一旦被设置就不能再改变。
对于数组来说不可变性有一点点不同。你还是不能做一些可能改变数组唱的的操作,但是你可以替换数组中已有的值。这样可以让Swift的数组在固定长度的时候提供更好地性能。
NOTE 当集合长度不需要改变的时候尽量要创建不可变的集合。这样Swift编译器可以优化你创建的集合的性能。