對(duì)于大部分現(xiàn)代化面向?qū)ο蟮木幊陶Z(yǔ)言都擁有結(jié)構(gòu)化的錯(cuò)誤處理語(yǔ)法特性渊季,swift也不例外。當(dāng)我們?cè)谝粋€(gè)方法或函數(shù)中實(shí)現(xiàn)某些功能時(shí),如果遇到錯(cuò)誤的用戶輸入則可能導(dǎo)致嚴(yán)重的異常問(wèn)題纵柿,此時(shí)我們可以選擇通過(guò)拋出異常的方式,將此錯(cuò)誤送給函數(shù)調(diào)用者启绰。
我們常用 try-catch 結(jié)構(gòu)昂儒,不過(guò)在swift編程語(yǔ)言中沒(méi)有引入專門的 try 語(yǔ)句塊,而是直接調(diào)用之前的 do 語(yǔ)句塊委可,僅僅將 try 作為拋出異常的函數(shù)或方法的標(biāo)識(shí)渊跋,然后在 do 語(yǔ)句塊后接 catch 語(yǔ)句塊捕獲錯(cuò)誤并進(jìn)行處理。
do {
let str = try String(contentsOfFile: "/Users/zennychen/Desktop/test.txt", encoding: String.Encoding.ascii)
print("content is: \(str)")
}
catch {
print("file read failed!")
}
第一節(jié) swift中錯(cuò)誤的表示
在 swift 中如果我們要定義一個(gè)表示錯(cuò)誤的類型非常簡(jiǎn)單,只要遵循 Error 協(xié)議就可以了拾酝,我們通常用枚舉或結(jié)構(gòu)體來(lái)表示錯(cuò)誤類型燕少,枚舉可能用的多些,因?yàn)樗芨庇^的表達(dá)當(dāng)前錯(cuò)誤類型的每種錯(cuò)誤細(xì)節(jié)微宝。
當(dāng)我們定義了一個(gè)錯(cuò)誤類型之后棺亭,可以實(shí)現(xiàn) Error 協(xié)議中擴(kuò)展默認(rèn)實(shí)現(xiàn)的只讀屬性 localizedDescription,用于描述當(dāng)前錯(cuò)誤對(duì)象的詳細(xì)信息
/// 定義一個(gè)枚舉類型的錯(cuò)誤類型
enum MyEnumError: Error {
case errorOne
case errorTwo
/// 實(shí)現(xiàn)Error協(xié)議的localizedDescription只讀實(shí)例屬性
var localizedDescription: String {
let desc = self == .errorOne ? "the first errror" : "the second error"
return "\(self): \(desc)"
}
}
/// 定義一個(gè)結(jié)構(gòu)體類型的錯(cuò)誤類型
struct MyStructError: Error {
var errCode: Int = 0
/// 實(shí)現(xiàn)Error協(xié)議的localizedDescription只讀實(shí)例屬性
var localizedDescription: String {
return "The error code is: \(errCode)"
}
}
print("The enum error is: \(MyEnumError.errorOne.localizedDescription)")
print("The struct error is: \(MyStructError().localizedDescription)")
第二節(jié) swift中的錯(cuò)誤拋出
如果我們?cè)谝粋€(gè)函數(shù)或方法中可能要拋出一個(gè)錯(cuò)誤蟋软,那么我們必須在該函數(shù)的形參列表后面镶摘,返回類型前面(即 -> 前面)添加 throws 關(guān)鍵字,以顯示告訴編譯器岳守,該函數(shù)可能會(huì)拋出錯(cuò)誤凄敢。
/// 定義一個(gè)foo函數(shù),
/// 它可能會(huì)拋出一個(gè)錯(cuò)誤湿痢,
/// 因此這里用throws限定涝缝。
/// 注意throws的位置
func foo(a: Int) throws -> Int {
if a < -10 {
// 如果a的值小于-10,
// 則拋出MyEnumError.errorOne
throw MyEnumError.errorOne
}
else if a > 10 {
// 如果a的值大于10譬重,
// 則拋出MyEnumError.errorTwo
throw MyEnumError.errorTwo
}
else if a == 0 {
// 如果a的值為0拒逮,
// 那么拋出MyStructError對(duì)象,
// 并且其errCode的值為-1
throw MyStructError(errCode: -1)
}
print("a = \(a)")
return a
}
// ref的類型為:(Int) throws -> Void
let ref = foo(a:)
第三節(jié) 錯(cuò)誤捕獲與處理
在Swift 編程語(yǔ)言中我們使用 do-catch 塊對(duì)錯(cuò)誤進(jìn)行捕獲臀规,當(dāng)我們?cè)谡{(diào)用一個(gè) throws 聲明的函數(shù)或方法時(shí)滩援,我們必須把調(diào)用語(yǔ)句放在 do 語(yǔ)句塊中,同時(shí) do 語(yǔ)句塊后面緊接著使用 catch 語(yǔ)句塊塔嬉。
當(dāng)我們?cè)?do 語(yǔ)句塊中調(diào)用了一個(gè)可能會(huì)拋出錯(cuò)誤的函數(shù)時(shí)玩徊,而此時(shí)該函數(shù)在執(zhí)行時(shí)確實(shí)拋出了錯(cuò)誤,我們?cè)?catch 語(yǔ)句塊匯總可以捕獲錯(cuò)誤并進(jìn)行處理谨究,一旦 do 語(yǔ)句塊中拋出錯(cuò)誤恩袱,接下來(lái)的代碼將不會(huì)被執(zhí)行,會(huì)跳到 catch 語(yǔ)句塊中胶哲,catch 語(yǔ)句塊中的代碼執(zhí)行完成后畔塔,其下面的代碼也會(huì)執(zhí)行,如果 do 語(yǔ)句塊中無(wú)錯(cuò)誤拋出鸯屿,catch 語(yǔ)句塊不會(huì)被執(zhí)行澈吨。
// 由于在以下語(yǔ)句中包含了對(duì)可拋出錯(cuò)誤的函數(shù)調(diào)用,
// 因此這里使用do語(yǔ)句塊將這些調(diào)用圍起來(lái)
do {
// 對(duì)于任一可能會(huì)拋出錯(cuò)誤的函數(shù)碾盟,
// 在調(diào)用前面都必須添加try關(guān)鍵字
var value = try foo(a: -100)
value += try foo(a: 100)
value += try foo(a: 0)
print("value = \(value)")
} // 下面緊接著使用catch語(yǔ)句塊
catch let err {
// 如果在do語(yǔ)句塊中有任一錯(cuò)誤拋出棚辽,
// 那么即會(huì)執(zhí)行此catch語(yǔ)句塊中的內(nèi)容
print("err is: \(err)")
}
// 無(wú)論上面do語(yǔ)句塊是否有錯(cuò)誤,
// 這句打印均會(huì)執(zhí)行
print("complete")