Swift学习笔记
根据《Swift编程权威指南》和 Swift官方文档 学习整理的Swift学习笔记,持续更新,中间有什么错误,欢迎大家留言讨论。
系列总目录
官方文档
三、容器(集合)
Swift提供了三种主要的集合类型,称为Array
数组,Set
集合和Dictionary
字典,用于存储值的集合。
数组是值的有序集合。set是唯一值的无序集合。字典是键-值关联的无序集合。
1、数组
数组是值的有序集合。数组的每个位置都用索引标记,任何值都可以在数组中出现多次。数组通常用于值的顺序很重要或者很有用的场合,但是值的顺序是否有意义并不是先决条件。
1.1 创建数组
- 声明一个数组
var stringList: Array<String>
这里创建了一个名为stringList的变量,类型是Array。<>
用来告诉stringList接受什么样的实例。
- 还有另一个语法可以声明数组。
var stringList: [String]
这里,方括号表示stringList是Array实例,而String表示stringList接受什么类型的值。注意:现在只是声明了stringList,还没有初始化。这意味着它还没有准备好接受String类型的实例。如果现在进行添加,会报错。
- 初始化数组
var stringList: [String] = ["String01","String02"]
数组字面量是用任意其包含的实例初始化数组的快捷语法。
像其他类型一样,数组可以利用Swift的类型推断能力来声明。
- 使用类型推断
var stringList = ["String01","String02"]
1.2 访问和修改数组
1.2.1 添加元素
var stringList = ["String01","String02"]
stringList.append("String03")
stringList.append("String04")
这里通过append()
函数向数组中添加元素。
1.2.2 删除元素
// 接 1.2.1 代码
stringList.remove(at: 1)
这里通过remove(at: )
函数删除了stringList中索引为1的元素。
数组下标从
0
开始
1.2.3 获取数组元素个数
// 接 1.2.2 代码
print(stringList.count) // 3
print(stringList.isEmpty) // false
通过count
属性获取数组元素个数。通过isEmpty
属性检查count属性是否等于0
。
1.2.4 用下标获取区间内的元素
var hobbies = ["football","basketball","PC Game","Android","music","running"]
print(hobbies[1...3])
打印结果:[“basketball”, “PC Game”, “Android”]
这里使用了方括号语法 [1...3]
,打印了下标索引从1开始到3的元素。
1.2.5 用下标给元素添加信息
var hobbies = ["basketball","PC Game","Android","music","running"]
print(hobbies) // ["basketball", "PC Game", "Android", "music", "running"]
hobbies[2] += " IOS"
print(hobbies) // ["basketball", "PC Game", "Android IOS", "music", "running"]
这里使用加法和赋值运算符 +=
来给索引2的元素增加文本。
1.2.6 替换数组元素
// 接 1.2.5 代码
hobbies[2] = "IOS"
print(hobbies) // ["basketball", "PC Game", "IOS", "music", "running"]
这里直接使用下标和赋值运算符=
将索引2处的元素赋一个新值。
1.2.7 插入新元素
var hobbies = ["basketball","PC Game","Android","music","running"]
hobbies.insert("IOS", at: 3)
print(hobbies)
// ["basketball", "PC Game", "IOS", "Android", "music", "running"]
这里使用insert(value, at: index)
在索引3的位置添加一个元素。第一个参数接受要添加到数组实例。第二个参数接受你想添加的元素在数组中的位置的索引。
1.2.8 使用+=
添加另一个数组的所有元素
var hobbies = ["football","basketball","PC Game","Android"];
var newHobbies = ["IOS","music","running"];
hobbies += newHobbies
print(hobbies)
// ["football", "basketball", "PC Game", "Android", "IOS", "music", "running"]
使用+=
可以直接将另一数组所有元素添加到现有数组。这里当然也可以for循环实现(麻烦,不推荐),如下代码所示,实现效果是一致的。
var hobbies = ["football","basketball","PC Game","Android"]
var newHobbies = ["IOS","music","running"];
for hobby in newHobbies {
hobbies.append(hobby)
}
print(hobbies)
1.3 遍历数组
1.3.1 使用for-in循环遍历数组
var hobbies = ["football","basketball","PC Game","Android","IOS","music","running"]
for item in hobbies {
print(item)
}
1.3.2 在区间中遍历
- 闭区间
for item in hobbies[2...4] {
print(item)
}
// PC Game;Android;IOS
- 半开区间
for item in hobbies[1..<3] {
print(item)
}
//basketball;PC Game
- 单侧区间
for item in hobbies[2...] { // 从索引2开始,遍历到最后
print(item)
}
//PC Game;Android;IOS;music;running
for item in hobbies[...2] { // 从头遍历到2开始
print(item)
}
//football;basketball;PC Game
1.3.3 使用enumerated()
方法来遍历数组
如果需要每个项目的整数索引及其值,可以使用enumerated()
方法来遍历数组。
var hobbies = ["basketball","PC Game","Android","music","running"]
for (index, value) in hobbies.enumerated() {
print("Item \(index + 1): \(value)")
}
/* 执行效果
Item 1: basketball
Item 2: PC Game
Item 3: Android
Item 4: music
Item 5: running
*/
- enumerated()方法搭配区间遍历
for (index, value) in hobbies[2...4].enumerated() {
print("Item \(index + 1): \(value)")
}
/*
Item 1: Android
Item 2: music
Item 3: running
*/
需要注意的是,此时index不再反应数组真实的索引位置。
1.4 数组相等
var hobbies = ["basketball","PC Game","Android","music"]
hobbies.append("running")
var newHobbies = ["PC Game","basketball","Android","music","running"]
print(hobbies==newHobbies) // false
数组元素一致,顺序不一致,数组也是不相等。下面修改为顺序一致。
var hobbies = ["basketball","PC Game","Android","music"]
hobbies.append("running")
var newHobbies = ["basketball","PC Game","Android","music","running"]
print(hobbies==newHobbies) // true
1.5 不可变数组
使用let
创建不可变数组。数组一旦创建,任何形式的修改,都会报错。
let hobbies = ["basketball","PC Game","Android","music"]
2、字典
字典(Dictionary)使用键值对(key-value pair)组织其内容的容器类型。字典的键映射到值。字典中的键必须是唯一的。这个要求意味着每个键都唯一地映射到对应的值。
2.1 创建字典
创建Swift字典的通用语法如下:var dict: Dictionary<key, value>
。
本节所有语法,均使用 key代表要填充的键,value代表填充的值
对于Swift中Dictionary类型的键,唯一的要求是其必须可散列(hashable):也就是每个Key必须提供一种机制让Dictionary保证任何给定的键都是唯一的。Swift的基本类型都是可散列的, 比如String
、Int
、Float
、Double
和Bool
。
获得一个Dictionary实例的不同方法。
var dict1: Dictionary<String, Double> = [:]
var dict2 = Dictionary<String, Double>()
var dict3: [String:Double] = [:]
var dict4 = [String:Double]()
这4种方法得到的是同样的结果:经过完整初始化的Dictionary类型的实例,以及其键值的类型信息。Key被设置为接受String类型的键,而Value被设置为接受Double类型的值。在这4种情况下,字典实例都是空的:没有键也没有值。
[:]
和()
语法有什么区别?本质上是一样的。
[:]
使用字面量语法创建Dictionary类型的空实例,并且会使用声明中提供的类型信息约束键和值。
()
语法则使用Dictionary类型默认认初始化方法,这个方法会准备一个空的字典实例。
- 填充字典
var movieRatings = ["Donnie Darko": 4, "Chungking Express": 5, "Dark City": 4]
2.2 访问和修改字典
2.2.1 获取字典个数
var commodities = ["iphone12":6299.00,"Mac mini":5099.00,"小米10pro":5799.00]
print("一共\(commodities.count)件商品。")
print(commodities.isEmpty) // false
// 一共3件商品
2.2.2 从字典中读取值
// 接2.2.1代码
let commodity = commodities["iphone12"]
从字典中访问值,需要提供与要获取的值关联的键。这里返回的commodity类型使Double?
,是因为也许不存该键并返回nil
,例如获取键为“iPhone11”的值。
2.2.3 修改值
// 接2.2.1代码
commodities["小米10pro"] = 5499.00
现在小米10pro降价优惠,直接使用[Key]
和赋值运算符=
修改值。
还有一种方式可以更新与字典的键相关联的值:updateVAlue(value, forKey: key)
。注意,这个方法返回可空类型,因为这个键可能不存在。因此把返回值赋给一个预期类型的可选项,并用可选项实例绑定来获取这个键的旧值会很有用。
2.2.4 更新值
// 接2.2.1代码
let oldPrice: Double? = commodities.updateValue(5499.00, forKey: "小米10pro")
if let lastPrice = oldPrice, let price = commodities["小米10pro"] {
print("Old price: \(lastPrice); current price: \(price)")
}
// Old price: 5799.0; current price: 5499.0
这里结果显示了小米10pro的原价和现价。
2.2.5 增加值
// 接2.2.1代码
commodities["Redmi Note 9"] = 999.00
2.2.6 删除值
// 接2.2.5代码
let remove = commodities.removeValue(forKey: "Redmi Note 9")
// remove: Optional(999.0)
这里把2.2.5处新增的“Redmi Note 9”删除。使用removeValue(forKey:)
方法接受一个键作为参数,将与其匹配的键值对删除。如果键存在并且已成功删除,这个方法还会返回其关联的值。
也可以通过把键的值设为nil
来删除。
// 接2.2.5代码
commodities["Redmi Note 9"] = nil
这两种方法本质是一样的,但这样写不会返回被删除键的值。
2.3 遍历字典
2.3.1 使用for-in循环遍历数组
var commodities = ["iphone12":6299.00,"Mac mini":5099.00,"小米10pro":5799.00]
for (key, value) in commodities {
print("name: \(key), price: \(value)")
}
/*
name: 小米10pro, price: 5499.0
name: iphone12, price: 6299.0
name: Mac mini, price: 5099.0
*/
2.3.2 只遍历键或值
通过.keys
只遍历键,通过.values
只遍历值。
for key in commodities.keys {
print("name: \(key)")
}
/*
name: 小米10pro
name: iphone12
name: Mac mini
*/
for value in commodities.values {
print("name: \(key)")
}
/*
price: 5499.0
price: 6299.0
price: 5099.0
*/
2.4 把字典转换为数组
var commodities = ["iphone12":6299.00,"Mac mini":5099.00,"小米10pro":5799.00]
let names = [String](commodities.keys)
// 或者通过Array()语法
let names2 = Array(commodities.keys)
let values = [Double](commodities.values)
// 或者
let values2 = Array(commodities.values)
2.5 不可变字典
let commodities = ["iphone12":6299.00,"Mac mini":5099.00,"小米10pro":5799.00]
通过let
声明的字典,一旦创建,不可以任何方式改变其值。
3、集合
集合Set
是一组互不相同的实例的无序组合。为了确保元素唯一,集合需要其元素符合Hashable协议, 就跟字典的键一样。
3.1 创建集合
- 声明一个空集合
var hobbies = Set<String>()
这里创建了一个Set实例,声明其持有String。目前集合是空的,现在使用数组的方式创建一个集合。
- 使用数组方式创建
var hobbies: Set<String> = ["football","PC Game","Android","music","running"]
- 使用数组加类型推断创建。
var hobbies: Set = ["football","PC Game","Android","music","running"]
Set
必须显式声明该类型。因为swift默认推断为数组Array
。
3.2 访问和修改集合
3.2.1 获取集合个数
和Array和Dictionary一样,使用count
属性获取个数,isEmpty
属性判断count是否等于0。
3.2.2 添加元素
var hobbies = Set<String>()
hobbies.insert("football")
hobbies.insert("PC Game")
hobbies.insert("running")
通过调用集合的insert(_:)
方法向集合中添加元素。
3.2.3 删除元素
// 接3.2.2
if let removedHobby = hobbies.remove("running") {
print("\(removedHobby)删除成功")
} else {
print("没有找到这个元素")
}
通过调用集合的remove(_:)
方法从集合中删除一个项目。和字典一样,该方法返回一个可选项。
3.2.4 检查是否包含某元素
// 接3.2.3
print(hobbies.contains("running")) // false
print(hobbies.contains("football")) // false
使用contains(_:)
方法检查集合是否包含特定元素。
3.3 遍历集合
// 接3.2.2
for hobby in hobbies {
print("\(hobby)")
}
3.4 执行集合操作
下图描绘了两个集合-a
和b
-,其中各个集合操作的结果由阴影区域表示。
- 图一:使用
intersection(_:)
方法创建仅具有两个集合共有的值的新集合。 - 图二:使用
symmetricDifference(_:)
方法可以创建一个新集合,不能同时包含两个集合中的值。 - 图三:使用
union(_:)
方法创建一个包含两个集合中所有值的新集合。 - 图四:使用
subtracting(_:)
方法创建一个新集合,其值不在指定集合中。
4.4.1 并集(图3)
合并两个集合所有元素。(合并后元素唯一)
var bag1 :Set = ["Apple","Orange","Banana"]
var bag2 :Set = ["Orange","Pineapple","pear","Apple"]
let bag = bag1.union(bag2)
// ["Pineapple", "Banana", "Apple", "Orange", "pear"]
4.4.2 交集(图1)
求两个集合共同的元素,组成一个新集合。
var bag1 :Set = ["Apple","Orange","Banana"]
var bag2 :Set = ["Orange","Pineapple","pear","Apple"]
let bag = bag1.intersection(bag2)
// ["Apple", "Orange"]
4.4.3 去除一个集合的元素(图4)
一个集合取处另外一个集合的元素,组成一个新集合。
var bag1 :Set = ["Apple","Orange","Banana"]
var bag2 :Set = ["Orange","Pineapple","pear","Apple"]
let newBag2 = bag2.subtracting(bag1) // 去除 "Apple","Orange"
// ["Pineapple", "pear"]
4.4.4 反向交集(图3)
去除两个集合共有元素,其他元素组成一个新集合。
var bag1 :Set = ["Apple","Orange","Banana"]
var bag2 :Set = ["Orange","Pineapple","pear","Apple"]
let bag = bag1.symmetricDifference(bag2)
// ["Pineapple", "Banana", "pear"]
4.4.5 检测两个集合是否有重复元素
isDisjoint(with: )
方法:两个集合没有任何重复元素,返回true
;否则,返回false
。
var bag1 :Set = ["Apple","Orange"]
var bag2 :Set = ["Pineapple","pear"]
var bag3 :Set = ["Banana","Apple"]
let disjoint = bag1.isDisjoint(with: bag2) // true
let disjoint2 = bag1.isDisjoint(with: bag3) // false