一、运算符
- 一元运算符(Unary operators):前缀(prefix)
!a,后缀(postfix)a!; - 二元运算符(Binary operators):
a + b; - 三元运算符(Ternary operators):
a ? b : c;
1.1 赋值运算符
// 1. 简单赋值
let b = 10
var a = 5
// 2. 按元组赋值
let (x, y) = (1, 2)
// 3. “不支持” if 判断赋值语句
if x = y { // 不能这么用,这里铁定抛编译错误
}
1.2 算术运算符
注意以下三个要点:
- Swift 默认不允许算术运算的值溢出,这有别于 C 和 Objective-C,若要允许溢出则需要使用溢出运算符(overflow operator),例如:
a &+ b; - Swift 支持运算符实现字符串拼接,例如:
"hello, " + "world"; - 求余运算符
-9 % 4的结果是-1,因为:-9 = (4 x -2) + -1;
1.3 Compound Assignment Operators
其实就是+=、-=、*=、/=,和 C 语言基本一样,Swift 中应该没有默认的++、--运算符。
1.4 比较运算符
和 C 语言一样:==、!=、>、<、>=、<=。Swift 还提供了===和!==用于判断两个引用是否指向相同的对象。
// 1. Swift 支持按元组比较,Swift 默认的元组比较元素个数最大限制是7
(1, "zebra") < (2, "apple") // true because 1 is less than 2; "zebra" and "apple" are not compared
(3, "apple") < (3, "bird") // true because 3 is equal to 3, and "apple" is less than "bird"
(4, "dog") == (4, "dog") // true because 4 is equal to 4, and "dog" is equal to "dog"
1.5 三元运算符
官方文档提到三元运算符可以简化代码,但是过度使用会降低代码的可读性。
// 1. Swift 的三元运算符语法
let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
1.6 Nil-Coalescing Operator
Swift 专门为可空类型设计:a ?? b,等价于a != nil ? a! : b,用于给可控类型a设置默认值b。
1.7 范围运算符
范围运算符用于生成范围区间Range,包括:
...:闭区间范围运算符,包括头尾;..<:半开区间范围运算符,包括头不包括尾;
// 1. 闭区间范围运算符,从 1 打到 5
for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
}
// 2. 半开区间范围运算符,下面用半开区间,因为到 count 索引会溢出
let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..<count {
print("Person \(i + 1) is called \(names[i])")
}
// 3. 单边1,从目标索引到末尾。打印结果:Brian Jack,也就是索引 2,3
for name in names[2...] {
print(name)
}
// 4. 单边2,从开头到目标索引。打印结果:Anna Alex Brian,也就是索引 0,1,2
for name in names[...2] {
print(name)
}
// 5. Swift 利用范围运算符取数组区间,牛逼
for name in names[..<2] {
print(name)
}
// 6. Swift 范围运算符返回结果就是个 Range
let range = ...5
range.contains(7) // false
range.contains(4) // true
range.contains(-1) // true
1.8 逻辑运算符
和 C 语言一样包括&&、||、!。下面一段话摘自官方文档,但是实际调试发现let res = (true || false && false)得到的res为true,也就是说&&优先级还是会高于||的。不知道是我理解错了,还是确实是错漏,看来还是尽量用()分隔吧。
Note: The Swift logical operators && and || are left-associative, meaning that compound expressions with multiple logical operators evaluate the leftmost subexpression first.
二、字符和字符串
Swift 的字符串操作语法比 Objective-C 简洁得多,支持+运算符拼接字符串,支持\()形式的字符串插值(interpolation)。Swift 的字符串由一系列编码无关的 Unicode 字符组成,而且支持以各种 Unicode 形式访问其中的字符。
注意:Swift 的
String和 Foundation 框架中的NSString是 bridged 的。Foundation 也对NSString做了String的接口扩展。也就是说,只要导入 Foundation,String就可以调用NSString定义的所有接口。
2.1 字符串字面量
Swift 的单行字符串并没什么特殊之处。
let someString = "Some string literal value"
但是多行字符就相当牛逼了。以下代码表示多行字符串,包括中间的空白行:
let quotation = """
The White Rabbit put on his spectacles. "Where shall I begin,
please your Majesty?" he asked.
"Begin at the beginning," the King said gravely, "and go on
till you come to the end; then stop."
"""
注意多行字符的有效区间是:"""起始符的下一行以及"""终结符的上一行之间。因此下面两个字符串头尾都不包含转行符,两者实际上是相等的。
let singleLineString = "These are the same."
let multilineString = """
These are the same.
"""
有时想让代码可读性更好想要在代码中转行,但是字符串内容不转行,此时使用\实现
let softWrappedQuotation = """
The White Rabbit put on his spectacles. "Where shall I begin, \
please your Majesty?" he asked.
"Begin at the beginning," the King said gravely, "and go on \
till you come to the end; then stop."
"""
Swift 声明多行字符串时,可以带缩进效果。Swift 的字符串内容会忽略"""起始符下一行起始的所有空格,作为多行字符串的整体缩进量。如下图所示,"""起始符下一行起始有 4 个空格,则该字符串会忽略后续所有行的前 4 个空格。
字面量中可以包含特殊字符,例如:
- 空字符
\0、反斜杠\\、制表符\t、转行符\n、回车\r、双引号\"、单引号\'; - 任意 Unicode 编码字符,用
\u{n}表示,其中n为 Unicode 编码值,为 1-8 位十六进制数;
Swift 多行字符串中单个双引号是不需要转义的,甚至两个连续的双引号也无需转义,仅当三个连续双引号时需要转义,方式有两种:1、只转义第一个双引号;2、三个双引号都转义。例程如下:
let threeDoubleQuotationMarks = """
Escaping the first quotation mark \"""
Escaping all three quotation marks \"\"\"
"""
有时想忽略字符串字面量中的转义字符,可以使用#符号实现。例如打印#"Line 1\nLine 2"#,出来的是一行内容“Line 1\nLine 2”。如果使用#后,又想转义其中的一些特殊字符则用\#符号实现,例如打印#"Line 1\#nLine 2"#,出来的就是两行内容。###"Line1\###nLine2"###具有相同的效果。#符号在多行字符串中的使用例程如下,可以不对#"""所包围的连续三个双引号进行转义。
let threeMoreDoubleQuotationMarks = #"""
Here are three more double quotes: """
"""#
2.2 创建字符串
创建空字符串,使用isEmpty方法判空
var emptyString = "" // empty string literal
var anotherEmptyString = String() // initializer syntax
// these two strings are both empty, and are equivalent to each other
if emptyString.isEmpty {
print("Nothing to see here")
}
// Prints "Nothing to see here"
字符串可编辑性,用var、let修饰符区分,与 Objective-C 不同
var variableString = "Horse"
variableString += " and carriage"
// variableString is now "Horse and carriage"
let constantString = "Highlander"
constantString += " and another Highlander"
// this reports a compile-time error - a constant string cannot be modified
Swift 的 String 是值类型,并按值传递,无论是赋值、用作参数传递,都会拷贝字符串的副本。字符串默认拷贝(copy-by-default)的特点,既可以保证编辑字符串内容时不会影响字符串来源,也可以保证外部对字符串来源的编辑不会影响内部的字符串。
2.3 字符串和字符
for character in "Dog!🐶" {
print(character)
}
// D
// o
// g
// !
// 🐶
let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"]
let catString = String(catCharacters)
print(catString)
// Prints "Cat!🐱"
2.4 字符串拼接
// 1. 使用+拼接
let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
// welcome now equals "hello there"
// 2. 使用+=拼接
var instruction = "look over"
instruction += string2
// instruction now equals "look over there"
// 3. 使用append拼接
let exclamationMark: Character = "!"
welcome.append(exclamationMark)
// welcome now equals "hello there!"
// 4. 多行拼接
let badStart = """
one
two
"""
let end = """
three
"""
print(badStart + end)
// Prints two lines:
// one
// twothree
let goodStart = """
one
two
"""
print(goodStart + end)
// Prints three lines:
// one
// two
// three
2.5 字符串插值
// 1. 普通插值
let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
// message is "3 times 2.5 is 7.5"
// 2. 纯字符串插值失败
print(#"Write an interpolated string in Swift using \(multiplier)."#)
// Prints "Write an interpolated string in Swift using \(multiplier)."
// 3. 纯字符串插值成功
print(#"6 times 7 is \#(6 * 7)."#)
// Prints "6 times 7 is 42."
2.6 Unicode
Unicode 是编码、表示、处理文本的跨平台国际标准。可以表示几乎任意语言的字符,并从文件或 web 页面等源中读写字符。Swift 的String对 Unicode 标准有完整的兼容。
Swift 的String是由 Unicode 一个或多个 Unicode 标量值构建而来。Unicode 标量值是 21 位二进制数。每个 Unicode 标量值都会对应一个名称,例如LATIN SMALL LETTER A、FRONT-FACING BABY CHICK。
Swift 的每个Character实例都代表一个 extended grapheme cluster。Extended grapheme cluster 是一个或多个 Unicode 标量值的串联成的序列,并生成一个 human-readable 的字符。
例如:字母é可以用LATIN SMALL LETTER E WITH ACUTE或者U+00E9表示;也可以用字母e(LATIN SMALL LETTER E, or U+0065)和COMBINING ACUTE ACCENT(U+0301)表示,后者使 Unicode-aware 文本渲染系统渲染字母e的动作转为渲染é。这两种情况中字母é都是一个字符同时代表了一个 extended grapheme cluster。区别是前者是一个 Unicode 标量值表示,后者是由两个 Unicode 标量值串联成的 extended grapheme cluster 表示。
// 1. Extended grapheme cluster 例子1
let eAcute: Character = "\u{E9}" // é
let combinedEAcute: Character = "\u{65}\u{301}" // e followed by ́
// eAcute is é, combinedEAcute is é
// 2. Extended grapheme cluster 例子2
let precomposed: Character = "\u{D55C}" // 한
let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ
// precomposed is 한, decomposed is 한
// 3. Extended grapheme cluster 例子3
let enclosedEAcute: Character = "\u{E9}\u{20DD}"
// enclosedEAcute is é⃝
// 4. Extended grapheme cluster 例子4
let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
// regionalIndicatorForUS is 🇺🇸
2.7 字符计数
Swift 字符计数的例子:
let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
print("unusualMenagerie has \(unusualMenagerie.count) characters")
// Prints "unusualMenagerie has 40 characters"
由于 Swift 使用 extended grapheme cluster 表示一个字符,因此字符串拼接未必会造成字符串长度变更。例如
var word = "cafe"
print("the number of characters in \(word) is \(word.count)")
// Prints "the number of characters in cafe is 4"
word += "\u{301}" // COMBINING ACUTE ACCENT, U+0301
print("the number of characters in \(word) is \(word.count)")
// Prints "the number of characters in café is 4"
注意:Extended grapheme clusters 可以由多个 Unicode 标量值组成。也就是说不同的字符串,以及相同字符串的不同表示,都可能造成字符串占用内存空间大小的差异。这导致了Swift 只有遍历这个字符串确定所有 extended grapheme clusters 边界后,才能确定字符串的长度。在处理长字符串时应尤其注意这一点。而且相同的字符串分别用
String的count属性以及NSString的length属性计算长度,可能会得到不同的结果。这是因为NSString是根据 UTF-16 编码的字符个数来计算字符串长度,而不是用 extended grapheme clusters。
2.8 访问和修改字符串
Swift 通过index系列方法访问字符串中的字符,接口有很多。String有startIndex和endIndex属性,分别表示字符串的第一个字符和最后一个字符后面的索引,若两者相等则表示空字符串。通过indices可以遍历所有索引。需要注意index必须不能越界。
// 1. 通过 index 访问字符串中的字符
let greeting = "Guten Tag!"
greeting[greeting.startIndex]
// G
greeting[greeting.index(before: greeting.endIndex)]
// !
greeting[greeting.index(after: greeting.startIndex)]
// u
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index]
// a
// 2. 访问字符串中的字符的错误示范
greeting[greeting.endIndex] // Error,越界
greeting.index(after: greeting.endIndex) // Error,越界
// 3. 遍历字符串中的字符
for index in greeting.indices {
print("\(greeting[index]) ", terminator: "")
}
// Prints "G u t e n T a g ! "
插入和删除
// 1. 字符串插入
var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)
// welcome now equals "hello!"
welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there!"
// 2. 字符串删除
welcome.remove(at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there"
let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
welcome.removeSubrange(range)
// welcome now equals "hello"
2.9 Substring类型
Substring是 Swift 的一种基本类型。Substring几乎支持String的所有方法,但是Substring只适用于短暂的使用场景,当需要长期保存Substring时,应将其转化为String类型。
let greeting = "Hello, world!"
let index = greeting.firstIndex(of: ",") ?? greeting.endIndex
let beginning = greeting[..<index] // 这里返回了 Substring 类型
// beginning is "Hello"
// Convert the result to a String for long-term storage.
let newString = String(beginning)
Substring和String的区别是,Substring复用了源字符串的部分内存空间或者用于存储其他Substring实例的部分内存空间。因此只要不修改Substring,就不需要考虑Substring的内存拷贝的性能花销问题。Substring之所以只适用于短暂的使用场景,是因为Substring复用了源字符串的内存空间,因此只要Substring还在使用,则源字符串占用的内存会一直得不到释放。下图展示了Substring和String之间的关系。
2.10 字符串比较
Swift 字符串支持运算符比较。
let quotation = "We're a lot alike, you and I."
let sameQuotation = "We're a lot alike, you and I."
if quotation == sameQuotation {
print("These two strings are considered equal")
}
// Prints "These two strings are considered equal"
需要注意 Swift 字符串判等是根据 extended grapheme clusters,而不是字符串的编码值。
// 1. 不同编码值的字符串也可能被判断为相等
// "Voulez-vous un café?" using LATIN SMALL LETTER E WITH ACUTE
let eAcuteQuestion = "Voulez-vous un caf\u{E9}?"
// "Voulez-vous un café?" using LATIN SMALL LETTER E and COMBINING ACUTE ACCENT
let combinedEAcuteQuestion = "Voulez-vous un caf\u{65}\u{301}?"
if eAcuteQuestion == combinedEAcuteQuestion {
print("These two strings are considered equal")
}
// Prints "These two strings are considered equal"
// 2. 即使两个字符串具有相同的文本渲染结果,但也可能被判断为不相等。
// 下面的例子是:英语中的拉丁字母"A"和俄语中的西里尔字母"A",虽然都显示为"A",但是两者是不相等的
let latinCapitalLetterA: Character = "\u{41}"
let cyrillicCapitalLetterA: Character = "\u{0410}"
if latinCapitalLetterA != cyrillicCapitalLetterA {
print("These two characters are not equivalent.")
}
// Prints "These two characters are not equivalent."
2.11 前缀和后缀
用hasPrefix(_:)和hasSuffix(_:)分别判断字符串是否具有某前缀和某后缀。
2.12 字符串的Unicode表示
写入文本时需要指定文本的编码方式,文本编码结果是由一些 code units 串联而成。例如:UTF-8字符串的 code unit 是 8 位二进制数;UTF-16是 16 位二进制数;UTF-32是 32 位二进制数。
Swift 支持几种获取字符串的表示:
- UTF-8(通过
utf8属性获取); - UTF-16(通过
utf16属性获取); - 21 位 Unicode 标量值集合,等价于 UTF-32 编码(通过
unicodeScalars属性获取);
注意:Swift 字符串的
unicodeScalars是UInt32类型的数组。
// 1. 获取字符串的 UTF-8 编码序列
for codeUnit in dogString.utf16 {
print("\(codeUnit) ", terminator: "")
}
print("")
// Prints "68 111 103 8252 55357 56374 "
// 2. 获取字符串的 UTF-16 编码序列
// 3. 获取字符串的 21 位 Unicode 标量值集合序列,其中 scalar 是`UnicodeScalar`类型,
for scalar in dogString.unicodeScalars {
print("\(scalar.value) ", terminator: "")
}
print("")
// Prints "68 111 103 8252 128054 "
// 3. 通过获取字符串的 21 位 Unicode 标量值集合序列遍历字符串的所有字符
for scalar in dogString.unicodeScalars {
print("\(scalar) ")
}
// D
// o
// g
// ‼
// 🐶
三、集合类型(容器)
Swift 提供了三种基本集合类型:数组、集合、字典。集合是否可修改,取决于集合被声明为var变量还是let常量。若声明为变量则可以修改集合,包括增删改操作;声明为常量则不能进行以上操作。
3.1 数组
Swift 数组的声明语法和 Objective-C 很不一样,使用[${ElementType}]声明数组的类型,完整形态是Array<${ElementType}>,其中${ElementType}是元素类型。数组支持+、+=运算符拼接数组,十分牛逼。数组扩展了丰富的操作方法,包括count、isEmpty、insert、remove、append、removeLast等等。
// 1.声明数组的基本语法
var someInts = [Int]()
print("someInts is of type [Int] with \(someInts.count) items.")
// Prints "someInts is of type [Int] with 0 items."
// 2. 修改数组的语法
someInts.append(3)
// someInts now contains 1 value of type Int
someInts = []
// someInts is now an empty array, but is still of type [Int]
// 3. 使用值创建数组
var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]
// 4. 用两个数组合成一个数组
var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
// anotherThreeDoubles is of type [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]
// 5. 声明数组字面量
var shoppingList: [String] = ["Eggs", "Milk"]
// shoppingList has been initialized with two initial items
// 6. 在类型推断的支持下,声明数组字面量可以省略类型
var shoppingList = ["Eggs", "Milk"]
// 7. 使用索引语法
var firstItem = shoppingList[0]
// firstItem is equal to "Eggs"
shoppingList[0] = "Six eggs"
// the first item in the list is now equal to "Six eggs" rather than "Eggs"
// 7. 高阶索引语法,使用范围运算符,牛逼
shoppingList[4...6] = ["Bananas", "Apples"]
// 8. 数组的遍历
for item in shoppingList {
print(item)
}
// 9. 数组的遍历,同时获取索引和值,牛逼
for (index, value) in shoppingList.enumerated() {
print("Item \(index + 1): \(value)")
}
3.2 集合
集合就是哈希表,集合元素类型必须符合Hashable协议。支持count、isEmpty、insert、remove、contains、count等方法,其中的sorted()方法可以返回对集合元素排序的结果。集合的遍历语法和数组的基本遍历语法一致。
// 1. 生成集合的基本语法
var letters = Set<Character>()
print("letters is of type Set<Character> with \(letters.count) items.")
// Prints "letters is of type Set<Character> with 0 items."
// 2. 声明集合字面量的语法
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// 3. 集合遍历
for genre in favoriteGenres {
print("\(genre)")
}
// Classical
// Jazz
// Hip hop
// 4. 有序遍历
for genre in favoriteGenres.sorted() {
print("\(genre)")
}
// Classical
// Hip hop
// Jazz
集合支持以下几种操作:
- 交集;
- 对称差集;
- 并集;
- 差集;

let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]
oddDigits.union(evenDigits).sorted()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
oddDigits.intersection(evenDigits).sorted()
// []
oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
// [1, 9]
oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
// [1, 2, 9]
集合支持以下几种关系判断:
- 子集;
- 超集;
- 无交集;
let houseAnimals: Set = ["🐶", "🐱"]
let farmAnimals: Set = ["🐮", "🐔", "🐑", "🐶", "🐱"]
let cityAnimals: Set = ["🐦", "🐭"]
houseAnimals.isSubset(of: farmAnimals)
// true
farmAnimals.isSuperset(of: houseAnimals)
// true
farmAnimals.isDisjoint(with: cityAnimals)
// true
3.3 字典
字典就是 K-V 形态的哈希表,字典的关键字类型必须符合Hashable协议。字典类型用[Key: Value]表示,完全形态是Dictionary<Key: Value>。字典字面量的表示和 Objective-C 不太一样,使用[]符号包围。字典修改元素的方法是updateValue(_:, forKey:)方法,移除元素用removeValue(forKey:)方法。字典也支持索引访问。
// 1. 声明空字典
var namesOfIntegers = [Int: String]()
// namesOfIntegers is an empty [Int: String] dictionary
// 2. 字典也支持索引
namesOfIntegers[16] = "sixteen"
// namesOfIntegers now contains 1 key-value pair
namesOfIntegers = [:]
// namesOfIntegers is once again an empty dictionary of type [Int: String]
// 3. 声明字典字面量
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
// 类型推断
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
// 4. 字典的遍历语法比较灵活,下面列出三种:遍历Key和Value、只遍历Key、只遍历Value
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
// LHR: London Heathrow
// YYZ: Toronto Pearson
for airportCode in airports.keys {
print("Airport code: \(airportCode)")
}
// Airport code: LHR
// Airport code: YYZ
for airportName in airports.values {
print("Airport name: \(airportName)")
}
// Airport name: London Heathrow
// Airport name: Toronto Pearson
四、控制流
Swift 支持一系列控制流语句,包括while、repeat-while、for-in循环语句,if、guard、switch判断语句,break、continue控制语句。
4.1 for-in循环
直接上代码。
// 1. for-in遍历数组
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
print("Hello, \(name)!")
}
// Hello, Anna!
// Hello, Alex!
// Hello, Brian!
// Hello, Jack!
// 2. or-in遍历字典
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
print("\(animalName)s have \(legCount) legs")
}
// cats have 4 legs
// ants have 6 legs
// spiders have 8 legs
// 3. 使用范围运算符
for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25
// 3. 使用范围运算符,包括闭区间和半开区间
let base = 3
let power = 10
var answer = 1
for _ in 1...power {
answer *= base
}
print("\(base) to the power of \(power) is \(answer)")
// Prints "3 to the power of 10 is 59049"
let minutes = 60
for tickMark in 0..<minutes {
// render the tick mark each minute (60 times)
}
// 4. 使用stride系列函数,生成步长数组
let minuteInterval = 5
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
// render the tick mark every 5 minutes (0, 5, 10, 15 ... 45, 50, 55)
}
let hours = 12
let hourInterval = 3
for tickMark in stride(from: 3, through: hours, by: hourInterval) {
// render the tick mark every 3 hours (3, 6, 9, 12)
}
4.2 while循环
While 循环有两种:while 和 repeat-while 语法如下
// 1. while语法
while condition {
statements
}
// 2. repeat-while语法
repeat {
statements
} while condition
4.3 条件语句
Swift 的if语句没什么特别,除了判断式不需要()包围。
var temperatureInFahrenheit = 30
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
}
// Prints "It's very cold. Consider wearing a scarf."
但是 Swift 的swift语言就强大的一批。基本语法如下,省略了啰嗦的break语句,代码得到了肉眼可见的简化。但是同时也不允许空的case体,否则提示编译错误,又引进了更精简的匹配多个case的语法。Swift 的switch的强大有以下几个方面:
- 支持整型数、浮点数、字符、字符串、以及这些类型的联合体的匹配;
- 缺省
break语句; - 支持多项匹配;
- 支持范围表达式匹配;
- 支持
where修饰语句; - 支持值动态绑定;
// 1. switch 缺省 break 语句
let someCharacter: Character = "z"
switch someCharacter {
case "a":
print("The first letter of the alphabet")
case "z":
print("The last letter of the alphabet")
default:
print("Some other character")
}
// Prints "The last letter of the alphabet"
// 2. 不允许空 case 体
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a": // Invalid, the case has an empty body
case "A":
print("The letter A")
default:
print("Not the letter A")
}
// This will report a compile-time error.
// 3. 多项 case 匹配语法
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":
print("The letter A")
default:
print("Not the letter A")
}
// Prints "The letter A"
// 4. 支持范围表达式匹配
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
let naturalCount: String
switch approximateCount {
case 0:
naturalCount = "no"
case 1..<5:
naturalCount = "a few"
case 5..<12:
naturalCount = "several"
case 12..<100:
naturalCount = "dozens of"
case 100..<1000:
naturalCount = "hundreds of"
default:
naturalCount = "many"
}
print("There are \(naturalCount) \(countedThings).")
// Prints "There are dozens of moons orbiting Saturn."
// 5. 支持按元组匹配
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
print("\(somePoint) is at the origin")
case (_, 0):
print("\(somePoint) is on the x-axis")
case (0, _):
print("\(somePoint) is on the y-axis")
case (-2...2, -2...2):
print("\(somePoint) is inside the box")
default:
print("\(somePoint) is outside of the box")
}
// Prints "(1, 1) is inside the box"
// 6. 支持临时值绑定
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
print("on the x-axis with an x value of \(x)")
case (0, let y):
print("on the y-axis with a y value of \(y)")
case let (x, y):
print("somewhere else at (\(x), \(y))")
}
// Prints "on the x-axis with an x value of 2"
// 7. 支持 where 修饰语句
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}
// Prints "(1, -1) is on the line x == -y"
// 8. 支持值、支持元组多项匹配
let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
print("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
print("\(someCharacter) is a consonant")
default:
print("\(someCharacter) is not a vowel or a consonant")
}
// Prints "e is a vowel"
let stillAnotherPoint = (9, 0)
switch stillAnotherPoint {
case (let distance, 0), (0, let distance):
print("On an axis, \(distance) from the origin")
default:
print("Not on an axis")
}
// Prints "On an axis, 9 from the origin"
4.4 控制变换语句
Swift 支持五种控制变换语句:
continue:用于循环控制,直接进入下一次循环迭代;break:用于循环控制和switch条件判断控制,直接跳出当前循环迭代,或直接跳出case匹配;fallthrough:用于switch条件判断控制,进入下一个case匹配;return:用于函数返回;throw:用于错误处理;
// 1. continue 语句
let puzzleInput = "great minds think alike"
var puzzleOutput = ""
let charactersToRemove: [Character] = ["a", "e", "i", "o", "u", " "]
for character in puzzleInput {
if charactersToRemove.contains(character) {
continue
}
puzzleOutput.append(character)
}
print(puzzleOutput)
// Prints "grtmndsthnklk"
// 2. break 语句
let numberSymbol: Character = "三" // Chinese symbol for the number 3
var possibleIntegerValue: Int?
switch numberSymbol {
case "1", "١", "一", "๑":
possibleIntegerValue = 1
case "2", "٢", "二", "๒":
possibleIntegerValue = 2
case "3", "٣", "三", "๓":
possibleIntegerValue = 3
case "4", "٤", "四", "๔":
possibleIntegerValue = 4
default:
break
}
if let integerValue = possibleIntegerValue {
print("The integer value of \(numberSymbol) is \(integerValue).")
} else {
print("An integer value could not be found for \(numberSymbol).")
}
// Prints "The integer value of 三 is 3."
// 3. fallthrough 语句
let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
description += " a prime number, and also"
fallthrough
default:
description += " an integer."
}
print(description)
// Prints "The number 5 is a prime number, and also an integer."
Swift 的while循环有种比较特殊的特性,可以命名循环,使用break或continue进行循环控制时,指定循环名,可以指定该语句具体控制的循环。
gameLoop: while square != finalSquare {
diceRoll += 1
if diceRoll == 7 { diceRoll = 1 }
switch square + diceRoll {
case finalSquare:
// diceRoll will move us to the final square, so the game is over
break gameLoop
case let newSquare where newSquare > finalSquare:
// diceRoll will move us beyond the final square, so roll again
continue gameLoop
default:
// this is a valid move, so find out its effect
square += diceRoll
square += board[square]
}
}
print("Game over!")
4.5 卫语句
卫语句guard类似于if,是条件判断控制语法。其特别之处在于其判断式对应的{}主体为空。当用if判断一个条件时,若该逻辑分支为空,则此时不得不将条件改为否定式,然而否定式又会影响代码可读性,因此gurad应运而生。guard语句是指判断式if分支为空,else分支存在处理逻辑。这种语法叫做 early exist。使用 early exist 有利于提高代码可读性。
func greet(person: [String: String]) {
guard let name = person["name"] else {
return
}
print("Hello \(name)!")
guard let location = person["location"] else {
print("I hope the weather is nice near you.")
return
}
print("I hope the weather is nice in \(location).")
}
greet(person: ["name": "John"])
// Prints "Hello John!"
// Prints "I hope the weather is nice near you."
greet(person: ["name": "Jane", "location": "Cupertino"])
// Prints "Hello Jane!"
// Prints "I hope the weather is nice in Cupertino."
4.6 检查API是否可用
if #available(iOS 10, macOS 10.12, *) {
// Use iOS 10 APIs on iOS, and use macOS 10.12 APIs on macOS
} else {
// Fall back to earlier iOS and macOS APIs
}
五、总结
- Swift 支持给可空类型指定默认值的空判断运算符
??; - Swift 类型支持逻辑运算符重载;
- Swift 支持范围运算符和步长函数
stride,范围运算符包括闭区间运算符...和半开区间范围运算符..<; - Swift 的多行字符串字面量使用
"""符号指定可以支持强大的功能,例如缩进量,换行等; - 给字符串运算符添加
#前缀表示忽略字符串中的转义字符; - 字符串支持
+、+=运算符拼接; - 字符串格式化输出语法十分简练,称为字符串插值,使用
\()符号插入变量; - Swift 的字符串是根据 extended grapheme clusters 切分字符,extended grapheme clusters 是一个或多个 21 位二进制的 Unicode 编码标量值(在 Swift 中则用 32 位的
Int类型值表示)的串联,串联可以形成字符。字符的 extended grapheme clusters 表示可能有多种,因此打印出来内容相同的字符串未必占用相同大小的内存空间,拼接字符串也未必会造成字符串长度改变; Substring子串并不等同与字符串,虽然使用起来基本相同,区别在于多个Subtring的拷贝可能会共享同一个源String的一块内存空间,因此不使用于字符串生命周期拉得比较长的场景,这种场景应该将Subtring转化为String保存;- Swift 的集合类型的特征和 Objective-C 差不多,需要注意声明字典字面量时使用
[]符号包围,数组可以用范围表达式取多个元素,不知道支不支持stride按步长取元素,可以试一试; - Swift 的
switch语句异常强大:- 支持整型数、浮点数、字符、字符串、以及这些类型的联合体的匹配;
- 缺省
break语句; - 支持多项匹配;
- 支持范围表达式匹配;
- 支持
where修饰语句; - 支持值动态绑定;
- Swift 支持
guard卫语句,用于快速返回场景,增强代码可读性; - Swift 支持对
while循环命名,可以指定break、continue具体控制哪个循环;