摘要: swift的異常錯(cuò)誤拋出以及其處理葱峡,使你的代碼更加健壯抡草,更加安全
tips:新手開(kāi)發(fā)一枚饰及,如有一些概念錯(cuò)誤,還請(qǐng)指正康震。原創(chuàng)文章燎含,轉(zhuǎn)載請(qǐng)注明出處。
2015年的wwdc大會(huì)之前腿短,swift還沒(méi)有異常錯(cuò)誤處理屏箍。這是個(gè)惹人非議的詬病。然而蘋(píng)果公司不負(fù)眾望橘忱,在swift2.0上發(fā)布了該項(xiàng)更新赴魁。下面我們來(lái)了解下try catch組合的異常處理機(jī)制
建立專(zhuān)屬的錯(cuò)誤類(lèi)型
在oc中,我們通常使用NSError來(lái)做對(duì)應(yīng)的錯(cuò)誤處理钝诚,在swift中颖御,要想使用try catch這套機(jī)制,錯(cuò)誤類(lèi)型必須滿(mǎn)足ErrorType協(xié)議凝颇,NSError也是符合這個(gè)協(xié)議的潘拱。枚舉是作為錯(cuò)誤展示的比較合適的數(shù)據(jù)結(jié)構(gòu)秉继。
下面我們來(lái)針對(duì)數(shù)組是否為空使用是否越界為例子,來(lái)聲明一個(gè)錯(cuò)誤類(lèi)型:
enum myError : ErrorType{
case NOCOUNT
case OVERCOUNT
}
在開(kāi)發(fā)中泽铛,可以根據(jù)具體環(huán)境需要尚辑,建立自己需要的錯(cuò)誤類(lèi)型。
拋出錯(cuò)誤的函數(shù)
有了錯(cuò)誤類(lèi)型之后盔腔,那就是在合適的時(shí)機(jī)去拋出這些錯(cuò)誤杠茬,如何拋出錯(cuò)誤呢?我們需要對(duì)我們的函數(shù)進(jìn)行一些簡(jiǎn)單的改造弛随。
/// 判斷數(shù)組使用是否安全
/// - parameter - myArray 使用的數(shù)組
/// - userCount使用的index
/// - returns: 該數(shù)組傳入位置的值
fun cuseArraySafe(myArray : NSArray,useCount : Int)throws->Int{
if myArray.count<1{
print("array is empty!")
throw myError.NOCOUNT
}else if(myArray.count>0&& myArray.count> useCount){
print("use safe")
return myArray[useCount]as!Int
}else{
print("use over count")
throw myError.OVERCOUNT
}
}
在參數(shù)之后瓢喉,返回值->之前,我們加入了throws這個(gè)關(guān)鍵字舀透,這樣我們的函數(shù)就可以使用throw拋出錯(cuò)誤了栓票。只需要在何時(shí)的判斷之后,拋出我們枚舉的錯(cuò)誤愕够,就完成了我們的基礎(chǔ)工作走贪。
機(jī)關(guān)已經(jīng)設(shè)置好了,夾子已經(jīng)放好了惑芭,就等著獵物上鉤了坠狡。讓我們開(kāi)始使用這套機(jī)關(guān)吧。
使用拋出錯(cuò)誤的函數(shù)
聲明有throws的函數(shù)必須使用do..try去實(shí)現(xiàn):
let arr :NSArray=NSArray.init(array: [1,2,3,4,5])
do{
let num =try useArraySafe(arr, useCount:6)
print("\(num)");
}catch myError.NOCOUNT{
print("array is empty!")
}catc hmyError.OVERCOUNT{
print("use over count")
}
do內(nèi)部是對(duì)函數(shù)的實(shí)現(xiàn)過(guò)程遂跟,在實(shí)現(xiàn)過(guò)程中逃沿,如果拋出了錯(cuò)誤,則會(huì)在do后面的catch中根據(jù)拋出錯(cuò)誤的類(lèi)型進(jìn)行處理幻锁,且要使用try去調(diào)用函數(shù)凯亮。此處例子拋出錯(cuò)誤使用的是if語(yǔ)句,降低了代碼的可讀性哄尔。如果使用guard語(yǔ)句的話假消,可以很自然地在內(nèi)部使用throw拋出錯(cuò)誤,且代碼可讀性高究飞。下面是guard的改寫(xiě)
/// 判斷數(shù)組使用是否安全
/// - parameter - myArray 使用的數(shù)組
/// - userCount使用的index
/// - returns: 該數(shù)組傳入位置的值
fun cuseArraySafe(myArray : NSArray,useCount : Int)throws->Int{
defer{
print("all done!")
}
guard(myArray.count>0&& myArray.count> useCount)else{
throw myError.USELESS
}
returnmyArray[useCount]as!Int
}
let arr :NSArray=NSArray.init(array: [1,2,3,4,5])
do{
let num = tryuseArraySafe(arr, useCount:6)
print("\(num)");
}catch myError.USELESS{
print("wrong")
}
在myError內(nèi)新增一個(gè)USELESS, 當(dāng)且僅當(dāng)數(shù)組不為空和數(shù)組不越界的時(shí)候才能使用置谦,否則錯(cuò)誤。
可以看到亿傅,我在原函數(shù)內(nèi)部添加了一個(gè)defer。defer的作用是瘟栖,在它所在作用域代碼執(zhí)行完畢葵擎,它負(fù)責(zé)擦屁股的,做一些最后的操作半哟。所以defer所處作用域的確認(rèn)十分重要酬滤。
不關(guān)心錯(cuò)誤類(lèi)型签餐,只關(guān)心出沒(méi)出錯(cuò)
有的時(shí)候,我們并不關(guān)心到底出什么錯(cuò)誤盯串,我們僅僅關(guān)心到底出沒(méi)出錯(cuò)氯檐。這時(shí)我們?cè)赿o內(nèi)調(diào)用函數(shù)的時(shí)候,僅僅需要在try后面加一個(gè)?就行了,如下:
do{
let num =try? useArraySafe(arr, useCount:6)
print("\(num)");
}catch myError.USELESS{
print("wrong")
}
這個(gè)時(shí)候体捏,會(huì)提示你后面的catch語(yǔ)句將不會(huì)被執(zhí)行冠摄,我們就可以忽略錯(cuò)誤類(lèi)型,只在沒(méi)出錯(cuò)的情況下調(diào)用函數(shù)成功几缭。使用try?還會(huì)將函數(shù)的返回值自動(dòng)轉(zhuǎn)化為optional類(lèi)型河泳。void返回值的函數(shù)try?后返回的是optional.None也就是nil。如果返回的事int類(lèi)型的100年栓,try?后返回的就是optional(100)拆挥。
不處理錯(cuò)誤異常
當(dāng)你十分有信心你的操作不會(huì)拋出錯(cuò)誤,不處理錯(cuò)誤異常某抓,你僅需要在try調(diào)用函數(shù)的時(shí)候加一個(gè)!就行了纸兔。但是一旦你的程序出現(xiàn)了錯(cuò)誤或者異常,那么使用try!的后果就是你的程序會(huì)crash否副,所以小心使用食拜。
總結(jié):使用ErrorType來(lái)聲明你的錯(cuò)誤類(lèi)型,在函數(shù)中使用throws來(lái)告訴編譯器副编,我這個(gè)函數(shù)調(diào)用有異常錯(cuò)誤拋出负甸,使用throw拋出你的錯(cuò)誤。在調(diào)用時(shí)使用do..try..catch的組合完成錯(cuò)誤異常處理痹届。try?和try!應(yīng)該在合適的時(shí)候使用呻待。