一、常量和變量
- 常量: 不可變的量, 使用
let修飾
let maximumNumberOfLoginAttempts = 10
- 變量: 可以修改值的量, 使用
var修飾
var currentLoginAttempt = 0
- 可以在一行中聲明多個(gè)常量或變量, 用逗號(hào)隔開(kāi)
var x = 0, y = 0, z = 0
注意: 如果在代碼中, 有不需要修改的值, 請(qǐng)使用
let關(guān)鍵字聲明為常量, 只將需要修改的值聲明為變量
二、類型標(biāo)注
- 在聲明常量和變量時(shí), 可以在常量或變量名的后面加上
: 類型名, 給常量或變量加上類型標(biāo)注
var welcomeMessage: String
: 類型名: 代表著是...類型, 所以這行代碼可以理解為:聲明一個(gè)類型為String, 名字為welcomMessage的變量類型為String的意思是可以存儲(chǔ)任意String類型的值可以在一行中定義多個(gè)同樣類型的變量, 用逗號(hào)分割, 并在最后一個(gè)變量名之后添加類型標(biāo)注
var red, green, blue: Double
三、常量和變量的命名
- 常量和變量可以包含任何字符, 包括Unicode字符:
let π = 3.14159
let 你好 = "你好世界"
let ???? = "dogcow"
常量與變量名不能包含數(shù)學(xué)符號(hào),箭頭,保留的(或者非法的)Unicode 碼位,連線與制表符。也不能以數(shù)字開(kāi)頭,但是可以在常量與變量名的其他地方包含數(shù)字。
當(dāng)聲明多個(gè)常量或變量時(shí), 這些常量名和變量名不能出現(xiàn)重復(fù), 不能改變其存儲(chǔ)值的類型, 同時(shí), 也不能將常量和變量互轉(zhuǎn)
注意: Swift中保留了一些關(guān)鍵字, 所以在命名時(shí)如果與關(guān)鍵字重名, 需要使用反引號(hào)(`)將關(guān)鍵字包圍的方式將其作為名字使用。請(qǐng)盡量避免使用關(guān)鍵字做為常量或變量名, 除非你別無(wú)選擇
四、輸出常量和變量
-
print(_:separator:terminator:): 是Swift中的輸出函數(shù)
1、參數(shù)解釋
- 第一個(gè)參數(shù)
_: 是我們需要輸出的項(xiàng), 如果是多個(gè)輸出項(xiàng), 可以使用逗號(hào),隔開(kāi)
print(1, 2, 3, "4", "5", "6")
控制臺(tái)打印:
1 2 3 4 5 6
- 第二個(gè)參數(shù)
separator: 表示多個(gè)輸出項(xiàng)之間, 在輸出時(shí)用什么分割, 默認(rèn)是空格, 所以上述代碼在打印時(shí), 每個(gè)項(xiàng)之間會(huì)有個(gè)空格分割
print(1, 2, 3, "4", "5", "6", separator: "-")
控制臺(tái)打印:
1-2-3-4-5-6
- 第三個(gè)參數(shù)
terminator: 當(dāng)print的結(jié)尾需要打印的字符, 默認(rèn)是換行符\n
// 使用默認(rèn)terminator參數(shù):
print(1, 2, 3, "4", "5", "6")
print(1, 2, 3, "4", "5", "6", separator: "-")
控制臺(tái)打印:
1 2 3 4 5 6
1-2-3-4-5-6
// 指定terminator參數(shù)為空格:
print(1, 2, 3, "4", "5", "6", terminator: " ")
print(1, 2, 3, "4", "5", "6", separator: "-")
控制臺(tái)打印:
1 2 3 4 5 6 1-2-3-4-5-6
2、字符串插值
- Swift中可以使用字符串插值的方式把常量名或變量名當(dāng)做占位符加入到
長(zhǎng)字符串中, Swift會(huì)用當(dāng)前常量或變量的值替換這些占位符 - 將常量或變量名放入圓括號(hào)中, 并在開(kāi)括號(hào)前使用反斜杠將其轉(zhuǎn)義:
let abc = "hellow"
print("\(abc) world!")
控制臺(tái)打印:
hellow world!
五、注釋
- 單行注釋
// 這是單行注釋
- 多行注釋
/* 這也是一個(gè)注釋
但是是多行的 */
- 嵌套注釋:
多行注釋可以嵌套另一個(gè)多行注釋
/* 這是一個(gè)多行注釋的開(kāi)頭
/* 這是第二個(gè)被嵌套的多行注釋 */
這是第一個(gè)多行注釋的結(jié)尾 */
使用多行注釋, 你可以快速方便的注釋掉一大段代碼, 即使這段代碼之中已經(jīng)含有多行注釋
六、分號(hào)
- Swift并不強(qiáng)制在每條語(yǔ)句的結(jié)尾處使用分號(hào)(
;), 當(dāng)然添加上也不算錯(cuò) - 但是有一種情況必須使用分號(hào), 就是將多條語(yǔ)句寫在同一行內(nèi)
let cat = "??"; print(cat)
// 輸出 "??"
七、整數(shù)
1、有符號(hào)和無(wú)符號(hào)類型
- 整數(shù)就是沒(méi)有小數(shù)部分的數(shù)字
- Swift提供了8、16、32和64位的有符號(hào)和無(wú)符號(hào)整數(shù)類型
let a: Int8 = 10
let b: Int16 = 10
let c: Int32 = 10
let d: Int64 = 10
let e: UInt8 = 10
let f: UInt16 = 10
let g: UInt32 = 10
let h: UInt64 = 10
2、整數(shù)范圍
- 可以訪問(wèn)不同整數(shù)類型的
min和max屬性來(lái)獲取對(duì)應(yīng)類型的最大值和最小值
let minValue = UInt8.min // minValue 為 0,是 UInt8 類型
let maxValue = UInt8.max // maxValue 為 255,是 UInt8 類型
-
min和max所傳回值的類型, 正是其所對(duì)的整數(shù)類型(如上例 UInt8, 所傳回的類型是 UInt8), 可用在表達(dá)式中相同類型值旁。
3、Int
- Swift提供了一個(gè)特殊的有符號(hào)類型
Int, 長(zhǎng)度與當(dāng)前平臺(tái)的原生字長(zhǎng)相同 - 在32位平臺(tái)上,
Int和Int32長(zhǎng)度相同 - 在64位平臺(tái)上,
Int和Int64長(zhǎng)度相同
4、UInt
- Swift 也提供了一個(gè)特殊的無(wú)符號(hào)類型
UInt,長(zhǎng)度與當(dāng)前平臺(tái)的原生字長(zhǎng)相同: - 在32位平臺(tái)上,
UInt和UInt32長(zhǎng)度相同。 - 在64位平臺(tái)上,
UInt和UInt64長(zhǎng)度相同。
八、浮點(diǎn)數(shù)
- 浮點(diǎn)數(shù)是有小數(shù)部分的數(shù)字, 比如
3.14159、0.1和-273.15。 - 浮點(diǎn)類型比整數(shù)類型表示的范圍更大, 可以存儲(chǔ)比
Int類型更大或者更小的數(shù)字。Swift提供了兩種有符號(hào)浮點(diǎn)數(shù)類型: -
Double表示64位浮點(diǎn)數(shù)。當(dāng)你需要存儲(chǔ)很大或者很高精度的浮點(diǎn)數(shù)時(shí)請(qǐng)使用此類型。 -
Float表示32位浮點(diǎn)數(shù)。精度要求不高的話可以使用此類型。
九、類型安全和類型推斷
1、類型安全
Swift是一個(gè)類型安全的語(yǔ)言。類型安全的語(yǔ)言可以讓開(kāi)發(fā)者更清楚地知道代碼要處理的值的類型
由于Swift是類型安全的, 所以會(huì)在編譯代碼時(shí)進(jìn)行類型檢查, 并把不匹配的類型標(biāo)記為錯(cuò)誤
如果你的代碼需要一個(gè) String, 你絕對(duì)不可能不小心傳進(jìn)去一個(gè) Int。如果傳入, 編譯器就會(huì)報(bào)錯(cuò)
let message: String = 10
// 報(bào)錯(cuò): Cannot convert value of type 'Int' to specified type 'String'
2、類型推斷
- 在聲明常量和變量時(shí), 并不需要顯示的指定類型, 編譯器會(huì)根據(jù)等號(hào)(
=)右面的值來(lái)推斷出當(dāng)前定義的常量和變量的類型
let meaningOfLife = 42
// meaningOfLife 會(huì)被推測(cè)為 Int 類型, 不需要寫成 let meaningOfLife: Int = 42
- 當(dāng)推斷浮點(diǎn)數(shù)的類型時(shí), Swift 總是會(huì)選擇 Double 而不是 Float。
let pi = 3.14159
// pi 會(huì)被推測(cè)為 Double 類型
- 如果表達(dá)式中同時(shí)出現(xiàn)了整數(shù)和浮點(diǎn)數(shù), 會(huì)被推斷為 Double 類型:
let anotherPi = 3 + 0.14159
// anotherPi 會(huì)被推測(cè)為 Double 類型
十、數(shù)值型字面量
- 整數(shù)字面量可以被寫作:
一個(gè)十進(jìn)制數(shù),沒(méi)有前綴
一個(gè)二進(jìn)制數(shù),前綴是 0b
一個(gè)八進(jìn)制數(shù),前綴是 0o
一個(gè)十六進(jìn)制數(shù),前綴是 0x
- 下面的所有整數(shù)字面量的十進(jìn)制值都是
17:
let decimalInteger = 17
let binaryInteger = 0b10001 // 二進(jìn)制的17
let octalInteger = 0o21 // 八進(jìn)制的17
let hexadecimalInteger = 0x11 // 十六進(jìn)制的17
- 如果一個(gè)十進(jìn)制數(shù)的指數(shù)為 exp,那這個(gè)數(shù)相當(dāng)于基數(shù)和10^exp 的乘積:
1.25e2 表示 1.25 × 10^2,等于 125.0。
1.25e-2 表示 1.25 × 10^-2,等于 0.0125。
- 如果一個(gè)十六進(jìn)制數(shù)的指數(shù)為 exp,那這個(gè)數(shù)相當(dāng)于基數(shù)和2^exp 的乘積:
0xFp2 表示 15 × 2^2,等于 60.0。
0xFp-2 表示 15 × 2^-2,等于 3.75。
十一、整數(shù)轉(zhuǎn)換
- 不同整數(shù)類型的變量和常量可以存儲(chǔ)不同范圍的數(shù)字。
-
Int8類型的常量或者變量可以存儲(chǔ)的數(shù)字范圍是-128~127, 而UInt8類型的常量或者變量能存儲(chǔ)的數(shù)字范圍是0~255。 - 如果數(shù)字超出了常量或者變量可存儲(chǔ)的范圍, 編譯的時(shí)候會(huì)報(bào)錯(cuò):
let cannotBeNegative: UInt8 = -1
// UInt8 類型不能存儲(chǔ)負(fù)數(shù),所以會(huì)報(bào)錯(cuò)
let tooBig: Int8 = Int8.max + 1
// Int8 類型不能存儲(chǔ)超過(guò)最大值的數(shù),所以會(huì)報(bào)錯(cuò)
- 當(dāng)兩種整數(shù)類型的數(shù)字進(jìn)行運(yùn)算時(shí), 需要將這兩種整數(shù)類型, 轉(zhuǎn)換成同一種類型之后, 再運(yùn)算
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
現(xiàn)在兩個(gè)數(shù)字的類型都是
UInt16,可以進(jìn)行相加。目標(biāo)常量twoThousandAndOne的類型被推斷為UInt16,因?yàn)樗莾蓚€(gè)UInt16值的和。SomeType(ofInitialValue)是調(diào)用Swift構(gòu)造器并傳入一個(gè)初始值的默認(rèn)方法。在語(yǔ)言內(nèi)部,UInt16有一個(gè)構(gòu)造器,可以接受一個(gè)UInt8類型的值,所以這個(gè)構(gòu)造器可以用現(xiàn)有的UInt8來(lái)創(chuàng)建一個(gè)新的UInt16
注意,你并不能傳入任意類型的值,只能傳入 UInt16 內(nèi)部有對(duì)應(yīng)構(gòu)造器的值。不過(guò)你可以擴(kuò)展現(xiàn)有的類型來(lái)讓它可以接收其他類型的值(包括自定義類型)
十二、整數(shù)和浮點(diǎn)數(shù)轉(zhuǎn)換
- 整數(shù)和浮點(diǎn)數(shù)的轉(zhuǎn)換必須顯式指定類型:
let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
// pi 等于 3.14159,所以被推測(cè)為 Double 類型
這個(gè)例子中, 常量
three的值被用來(lái)創(chuàng)建一個(gè)Double類型的值, 所以加號(hào)兩邊的數(shù)類型須相同。如果不進(jìn)行轉(zhuǎn)換, 兩者無(wú)法相加。浮點(diǎn)數(shù)到整數(shù)的反向轉(zhuǎn)換同樣行, 整數(shù)類型可以用 Double 或者 Float 類型來(lái)初始化:
let integerPi = Int(pi)
// integerPi 等于 3, 所以被推測(cè)為 Int 類型
- 當(dāng)用這種方式來(lái)初始化一個(gè)新的整數(shù)值時(shí), 浮點(diǎn)值會(huì)被截?cái)?。也就是說(shuō) 4.75 會(huì)變成 4, -3.9 會(huì)變成 -3。
注意
結(jié)合數(shù)字類常量和變量不同于結(jié)合數(shù)字類字面量。字面量 3 可以直接和字面量 0.14159 相加,因?yàn)閿?shù)字字面量本身沒(méi)有明確的類型。它們的類型只在編譯器需要求值的時(shí)候被推測(cè)。
十三、類型別名
- Swift中, 可以給現(xiàn)有的類型起一個(gè)新的名字, 使用關(guān)鍵字
typealias, 新名與原始名用法一致
typealias AudioSample = Int8
- 定義了一個(gè)類型別名之后, 你可以在任何使用原始名的地方使用別名:
let min = AudioSample.min
let max = AudioSample.max
print(min, max)
// 控制臺(tái)打印: -128 127
十四、布爾值
- Swift中有一個(gè)基本的布爾類型, 叫做
Bool, 布爾值指邏輯上的值, 因?yàn)樗荒苁?真或者假 - Swift有兩個(gè)布爾常量,
true和false
let orangesAreOrange = true
let turnipsAreDelicious = false
// orangesAreOrange 和 turnipsAreDelicious 的類型會(huì)被推斷為 Bool, 因?yàn)樗鼈兊某踔凳遣紶栕置媪?
- 當(dāng)你編寫條件語(yǔ)句比如
if語(yǔ)句的時(shí)候,布爾值非常有用:
if turnipsAreDelicious {
print("Mmm, tasty turnips!")
} else {
print("Eww, turnips are horrible.")
}
// 輸出 "Eww, turnips are horrible."
- 如果在需要使用
Bool類型的地方使用了非布爾值, Swift的類型安全機(jī)制會(huì)報(bào)錯(cuò), 下面的例子會(huì)報(bào)告一個(gè)編譯時(shí)錯(cuò)誤:
let i = 1
if i {
// 這個(gè)例子不會(huì)通過(guò)編譯,會(huì)報(bào)錯(cuò)
}
- 然而, 下面的例子是合法的:
let i = 1
if i == 1 {
// 這個(gè)例子會(huì)編譯成功
}
// i == 1 的比較結(jié)果是 Bool 類型,所以可以通過(guò)類型檢查
十五、元組
- 元組: 把多個(gè)值組合成一個(gè)復(fù)合值, 元組內(nèi)的值可以是任意類型, 并不要求是相同類型
let http404Error = (404, "Not Found")
// http404Error 的類型是 (Int, String),值是 (404, "Not Found")
- 可以將元組的內(nèi)容分解成單獨(dú)的常量或變量
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
// 輸出 "The status code is 404"
print("The status message is \(statusMessage)")
// 輸出 "The status message is Not Found"
- 如果你只需要一部分元組值, 分解的時(shí)候可以把要忽略的部分用下劃線(
_)標(biāo)記:
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// 輸出 "The status code is 404"
- 此外還可以通過(guò)下標(biāo)訪問(wèn)元組中的單個(gè)元素, 下標(biāo)從零開(kāi)始:
print("The status code is \(http404Error.0)")
// 輸出 "The status code is 404"
print("The status message is \(http404Error.1)")
// 輸出 "The status message is Not Found"
- 可以在定義元組的時(shí)候給單個(gè)元素命名:
let http200Status = (statusCode: 200, description: "OK")
- 給元組中的元素命名后, 可以通過(guò)名字來(lái)獲取這些元素的值:
print("The status code is \(http200Status.statusCode)")
// 輸出 "The status code is 200"
print("The status message is \(http200Status.description)")
// 輸出 "The status message is OK"
- 元組做為函數(shù)的返回值時(shí), 會(huì)非常有用, 可以返回多個(gè)值
注意
元組在臨時(shí)組織值的時(shí)候很有用, 但是并不適合創(chuàng)建復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。如果你的數(shù)據(jù)結(jié)構(gòu)并不是臨時(shí)使用, 請(qǐng)使用類或者結(jié)構(gòu)體而不是元組
十六、可選類型
1、可選類型
- 在OC中, 給對(duì)象賦值, 或者方法返回一個(gè)對(duì)象時(shí), 可以使用
nil, 來(lái)表示缺少一個(gè)合法的對(duì)象
NSString *name = nil;
- 在Swift中, 一個(gè)非可選類型的值, 是不能賦值為
nil的
var abc: Int = nil
// 這是錯(cuò)誤的, abc的類型是 Int, 并不是可選類型 Int?
- 可選類型的
類型名, 就是在類型名的后面加一個(gè)問(wèn)號(hào), 例如:Int?, String?, Double?等 - 一個(gè)可選的
Int被寫作Int?, 問(wèn)號(hào)表示包含的值是可選類型, 也就是說(shuō)可能包含Int值, 也可能不包含值
2、nil
- 可以給變量賦值為
nil, 來(lái)表示它沒(méi)有值:
var serverResponseCode: Int? = 404
// serverResponseCode 包含一個(gè)可選的 Int 值 404
serverResponseCode = nil
// serverResponseCode 現(xiàn)在不包含值
注意
Swift的nil和OC中的nil并不一樣, 在OC中,nil是一個(gè)指向不存在對(duì)象的指針。在Swift中,nil不是指針, 它是一個(gè)確定的值, 用來(lái)表示值缺失。任何類型的可選狀態(tài)都可以被設(shè)置為nil,不只是對(duì)象類型。
3、if 語(yǔ)句判斷
- 可以使用
if語(yǔ)句和nil比較來(lái)判斷一個(gè)可選值是否包含值 - 如果可選類型有值, 他將不等于nil
if convertedNumber != nil {
print("convertedNumber contains some integer value.")
}
// 輸出 "convertedNumber contains some integer value."
4、強(qiáng)制解析
- 一個(gè)可選類型的變量, 打印如下
var abc: Int? = nil
print(abc) // 打印: nil
abc = 123
print(abc) // 打印: Optional(123)
可選類型的變量不能直接使用, 因?yàn)樗念愋褪?code>Optional, 表示有值或者空值, 如果想要使用可選類型的變量, 就必須對(duì)該變量進(jìn)行解包
當(dāng)確定可選類型確實(shí)包含值之后(非
nil), 可以在可選的名字后面加一個(gè)感嘆號(hào)(!)來(lái)獲取值, 這個(gè)感嘆號(hào)表示我知道這個(gè)可選有值, 非nil, 請(qǐng)使用它, 這被稱為可選值的強(qiáng)制解析
注意:
使用!來(lái)獲取一個(gè)不存在的可選值會(huì)導(dǎo)致運(yùn)行錯(cuò)誤, 使用(!)來(lái)強(qiáng)制解析之前, 一定要確定可選包含一個(gè)非nil的值
5、可選綁定(if let)
可選綁定: 可以判斷一個(gè)可選類型是否有值, 如果有值就會(huì)把這個(gè)值賦給一個(gè)臨時(shí)常量或者變量
可選綁定可以用在
if和while語(yǔ)句中,這條語(yǔ)句不僅可以用來(lái)判斷可選類型中是否有值,同時(shí)可以將可選類型中的值賦給一個(gè)常量或者變量。未使用可選綁定
let abc: Int? = 123
print(abc) // 打印: Optional(123)
- 使用
if let可選綁定
var abc: Int? = 123
if let def = abc {
print(def) // 打印: 123
}
- 使用
while let可選綁定
let abc: Int? = 123
while let abc = abc {
print(abc) // 打印: 123
break;
}
可以將
lf let改為lf var, 這樣def就是一個(gè)變量而非常量可以使用多個(gè)可選綁定或多個(gè)布爾條件包含在一個(gè)if語(yǔ)句中
if let firstNumber = Int("4"),
let secondNumber = Int("42"),
firstNumber < secondNumber
&& secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
// 輸出 "4 < 42 < 100"
if let firstNumber = Int("4") {
if let secondNumber = Int("42") {
if firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
}
}
// 輸出 "4 < 42 < 100"
注意:
在if條件語(yǔ)句中使用常量或變量來(lái)創(chuàng)建一個(gè)可選綁定, 僅在if語(yǔ)句的句中body中才能獲取到值, while語(yǔ)句亦然
6、可選綁定
有時(shí)候在程序架構(gòu)中, 第一次被賦值之后, 可以確定一個(gè)可選類型在之后會(huì)一直有值, 在這種情況下, 每次都要判斷和解析可選值是非常低效的, 因?yàn)榭梢源_定它總會(huì)有值
這種情況下, 可以將可選類型定義為隱式解析可選類型, 把想要用作可選的類型的后面的問(wèn)號(hào)(
String?)改成感嘆號(hào)(String!)來(lái)聲明一個(gè)隱式解析可選類型一個(gè)隱式解析可選類型其實(shí)就是一個(gè)普通的可選類型, 直接打印如下:
var abc: String! = nil
print(abc) // 打印: none
abc = "123"
print(abc) // 打印: some("123")
- 但是可以被當(dāng)做非可選類型來(lái)使用,并不需要每次都使用解析來(lái)獲取可選值
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // 需要感嘆號(hào)來(lái)獲取值
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // 不需要感嘆號(hào)
注意
如果在隱式解析可選類型沒(méi)有值的時(shí)候嘗試取值, 會(huì)觸發(fā)運(yùn)行時(shí)錯(cuò)誤, 和在沒(méi)有值的普通可選類型后面加一個(gè)感嘆號(hào)一樣
- 仍然可以把隱式解析可選類型當(dāng)做普通可選類型來(lái)判斷是否包含值:
if assumedString != nil {
print(assumedString)
}
// 輸出 "An implicitly unwrapped optional string."
- 也可以在可選綁定中使用隱式解析可選類型來(lái)檢查并解析它的值
if let definiteString = assumedString {
print(definiteString)
}
// 輸出 "An implicitly unwrapped optional string."
注意
如果一個(gè)變量之后可能變成nil的話請(qǐng)不要使用隱式解析可選類型, 如果你需要在變量的生命周期中判斷是否是nil的話, 請(qǐng)使用普通可選類型
十七、錯(cuò)誤處理
- 當(dāng)一個(gè)函數(shù)遇到錯(cuò)誤條件, 它能夠報(bào)錯(cuò)
func canThrowAnError() throws {
// 這個(gè)函數(shù)有可能拋出錯(cuò)誤
}
- 一個(gè)函數(shù)可以通過(guò)聲明中添加
throws關(guān)鍵詞來(lái)拋出錯(cuò)誤消息, 當(dāng)你的函數(shù)能跑出錯(cuò)誤消息時(shí), 你應(yīng)該在表達(dá)式中前置try關(guān)鍵詞, 并使用do catch接受錯(cuò)誤
do {
try canThrowAnError()
// 沒(méi)有錯(cuò)誤消息拋出
} catch {
// 有一個(gè)錯(cuò)誤消息拋出
}
- 一個(gè)
do語(yǔ)句創(chuàng)建了一個(gè)新的包含作用域,使得錯(cuò)誤能被傳播到一個(gè)或多個(gè)catch從句。
十八、斷言和先決條件
斷言和先決條件是在運(yùn)行時(shí)所做的檢查, 可以用他們來(lái)檢查在執(zhí)行后續(xù)代碼之前, 某一個(gè)必要的條件是否已經(jīng)被滿足了
如果斷言或者先決條件中的布爾條件評(píng)估為
true, 則代碼像往常一樣繼續(xù)執(zhí)行, 如果評(píng)估為false, 程序的當(dāng)前狀態(tài)無(wú)效, 代碼執(zhí)行結(jié)束, 程序終止斷言幫助我們?cè)陂_(kāi)發(fā)階段找到錯(cuò)誤和不正確的假設(shè), 先決條件幫助我們?cè)谏a(chǎn)環(huán)境中檢測(cè)到存在的問(wèn)題
斷言和先決條件的不同點(diǎn)
斷言僅在調(diào)試環(huán)境運(yùn)行,而先決條件則在調(diào)試環(huán)境和生產(chǎn)環(huán)境中運(yùn)行。
在生產(chǎn)環(huán)境中,斷言的條件將不會(huì)進(jìn)行評(píng)估。
這個(gè)意味著你可以使用很多斷言在你的開(kāi)發(fā)階段,但是這些斷言在生產(chǎn)環(huán)境中不會(huì)產(chǎn)生任何影響。
1、使用斷言進(jìn)行調(diào)試
- 可以調(diào)用Swift標(biāo)準(zhǔn)庫(kù)的
assert(_:_:file:line:)函數(shù)寫一個(gè)斷言 - 向這個(gè)函數(shù)傳入一個(gè)結(jié)果為
true或者false的表達(dá)式以及一條信息, 當(dāng)表達(dá)式的結(jié)果為false的時(shí)候這條信息會(huì)被顯示
let age = -3
assert(age > 0, "年齡必須大于0")
// 因?yàn)?age < 0,所以斷言會(huì)觸發(fā)
- 如果不需要斷言信息, 可以省略掉
assert(age >= 0)
- 如果已經(jīng)使用代碼檢查了條件, 例如使用
if語(yǔ)句判斷, 可以使用assertionFailure(_:file:line:)函數(shù)來(lái)表明錯(cuò)誤信息
if age > 10 {
print("You can ride the roller-coaster or the ferris wheel.")
} else if age > 0 {
print("You can ride the ferris wheel.")
} else {
// 如果走入這里, 調(diào)試階段會(huì)直接中斷程序
assertionFailure("A person's age can't be less than zero.")
}
2、強(qiáng)制執(zhí)行先決條件
當(dāng)一個(gè)條件可能為假,但是繼續(xù)執(zhí)行代碼要求條件必須為真的時(shí)候,需要使用先決條件
可以使用全局
precondition(_:_:file:line:)函數(shù)來(lái)寫一個(gè)先決條件, 向這個(gè)函數(shù)傳入一個(gè)結(jié)果為true或者false的表達(dá)式以及一條信息, 當(dāng)表達(dá)式的結(jié)果為false的時(shí)候這條信息會(huì)被顯示:
// 在一個(gè)下標(biāo)的實(shí)現(xiàn)里...
let index = -1
precondition(index > 0, "Index must be greater than zero.")
注意
如果你使用 unchecked 模式(-Ounchecked)編譯代碼,先決條件將不會(huì)進(jìn)行檢查。編譯器假設(shè)所有的先決條件總是為 true(真),他將優(yōu)化你的代碼。
- 你能使用
fatalError(_:file:line:)函數(shù)在設(shè)計(jì)原型和早期開(kāi)發(fā)階段,這個(gè)階段只有方法的聲明,但是沒(méi)有具體實(shí)現(xiàn),你可以在方法體中寫上fatalError("Unimplemented")作為具體實(shí)現(xiàn)。因?yàn)?fatalError不會(huì)像斷言和先決條件那樣被優(yōu)化掉,所以你可以確保當(dāng)代碼執(zhí)行到一個(gè)沒(méi)有被實(shí)現(xiàn)的方法時(shí),程序會(huì)被中斷。