Swift: 基礎(chǔ)部分

Swift中文文檔

一、常量和變量

  • 常量: 不可變的量, 使用 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ù)類型的minmax屬性來(lái)獲取對(duì)應(yīng)類型的最大值和最小值
let minValue = UInt8.min // minValue 為 0,是 UInt8 類型
let maxValue = UInt8.max // maxValue 為 255,是 UInt8 類型
  • minmax 所傳回值的類型, 正是其所對(duì)的整數(shù)類型(如上例 UInt8, 所傳回的類型是 UInt8), 可用在表達(dá)式中相同類型值旁。
3、Int
  • Swift提供了一個(gè)特殊的有符號(hào)類型Int, 長(zhǎng)度與當(dāng)前平臺(tái)的原生字長(zhǎng)相同
  • 在32位平臺(tái)上, IntInt32長(zhǎng)度相同
  • 在64位平臺(tái)上, IntInt64長(zhǎng)度相同
4、UInt
  • Swift 也提供了一個(gè)特殊的無(wú)符號(hào)類型 UInt,長(zhǎng)度與當(dāng)前平臺(tái)的原生字長(zhǎng)相同:
  • 在32位平臺(tái)上,UIntUInt32 長(zhǎng)度相同。
  • 在64位平臺(tái)上,UIntUInt64 長(zhǎng)度相同。

八、浮點(diǎn)數(shù)

  • 浮點(diǎn)數(shù)是有小數(shù)部分的數(shù)字, 比如 3.141590.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è)布爾常量, truefalse
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í)常量或者變量

  • 可選綁定可以用在 ifwhile 語(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ì)被中斷。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容