do-try-catch錯(cuò)誤處理模式
Swift2.x拋棄了cocoa的錯(cuò)誤處理模式,使用了do-try-catch錯(cuò)誤處理模式
cocoa的錯(cuò)誤處理模式
let contents = NSString(contentsOfFile: filePath, encoding: NSUTF8StringEncoding, error: nil)
或者
var err: NSError?
let contents = NSString(contentsOfFile: filePath, encoding: NSUTF8StringEncoding, error: err)
由于Objective-C和Swift1.x沒(méi)有強(qiáng)制處理機(jī)制,因此一旦真的發(fā)生錯(cuò)誤,程序就會(huì)崩潰。
do-try-catch錯(cuò)誤模式
do {
let str = try NSString(contentsOfFile: filePath, encoding: NSUTF8StringEncoding)
} catch let err as NSError {
print(err.description)
}
注: do-tyr-catch這種錯(cuò)誤模式與Java中異常處理機(jī)制非常類似,本意就是嘗試( try )做一件事情,如果失敗則捕獲( catch )處理。
捕獲錯(cuò)誤
完整的do-try-catch錯(cuò)誤處理模式語(yǔ)法如下:
do {
try 語(yǔ)句
成功處理語(yǔ)句組
} catch 匹配錯(cuò)誤 {
錯(cuò)誤處理語(yǔ)句組
}
錯(cuò)誤類型
在Swift中錯(cuò)誤類型必須遵從Error Type協(xié)議,其次是考慮錯(cuò)誤類型的匹配,它應(yīng)該設(shè)計(jì)為枚舉類型,因?yàn)槊杜e類型非常適合將一組相關(guān)值關(guān)聯(lián)起來(lái)。
enum DAOError: Error {
case NOData
case PrimaryKeyNull
}
do {
//try 訪問(wèn)數(shù)據(jù)表函數(shù)或方法
} catch DAOError.NOData {
print("沒(méi)有數(shù)據(jù)。")
}catch DAOError.PrimaryKeyNull {
print("主鍵為空。")
}
在函數(shù)或方法中拋出錯(cuò)誤
- 在函數(shù)或方法中通過(guò)throw語(yǔ)句人為地拋出錯(cuò)誤
- 在函數(shù)或方法中調(diào)用其他可以拋出錯(cuò)誤的函數(shù)或方法,但是沒(méi)有捕獲處理,會(huì)導(dǎo)致錯(cuò)誤被傳播出來(lái)。
//刪除Note 方法
func remove(model: Note) throws {
guard let date = model.data else {
//拋出“主鍵為空”錯(cuò)誤
throw DAOError.PrimaryKeyNull
}
//比較日期主鍵是否相等
for (index, note) in listData.enumerate() where note.date == date {
listData.removeIndex(index)
}
}
//查詢所有數(shù)據(jù)方法
func findAll() throws -> [Note] {
guard listData.count > 0 else {
//拋出“沒(méi)有數(shù)據(jù)”錯(cuò)誤
throw DAOError.NoData
}
return listData
}
func printNotes() throws {
let datas = try findAll()
for note in datas {
print("data: \(note.date!) - content:\(note.content!)")
}
}
try printNotes()
1、remove方法我們聲明為有可能發(fā)生錯(cuò)誤,加了個(gè)throws, 如果 let date = model.date 成立的話,走for語(yǔ)句,否則拋出異?!?throw DAOError.PrimaryKeyNull”,跳出程序代碼。
2、findAll方法我們聲明為有可能發(fā)生錯(cuò)誤,加了個(gè)throws, 有返回值[Note],如果“l(fā)istData.count > 0” 成立,返回listData,否則拋出異常。
3、printNotes方法我們聲明為有可能發(fā)生錯(cuò)誤,加了個(gè)throws。
方法內(nèi)部調(diào)用findAll方法,即在printNotes方法中調(diào)用了可以拋出錯(cuò)誤的findAll方法,所以前面要加try,但卻沒(méi)有用catch捕獲處理這個(gè)錯(cuò)誤,一旦發(fā)生錯(cuò)誤,捕獲不到錯(cuò)誤,方法不會(huì)繼續(xù)往下走,跳出方法,往下傳播,傳播它的上層調(diào)用者,把錯(cuò)誤給上層調(diào)用者,上層調(diào)用者還是處理不了的話,在往下傳,最后傳到運(yùn)行環(huán)境,然后崩潰。
4、調(diào)用“try printNotes()” ,會(huì)調(diào)用printNotes方法, 調(diào)用printNotes方法又會(huì)調(diào)用findAll方法,如果findAll方法中有錯(cuò)誤發(fā)生的情況下,錯(cuò)誤傳遞給findAll方法,findAll方法又會(huì)傳遞給printNotes方法,然后再傳遞給“try printNotes”。如果“try printNotes”也不捕獲的話就會(huì)傳遞給運(yùn)行環(huán)境,運(yùn)行環(huán)境遇到錯(cuò)誤后就會(huì)崩掉。
注:對(duì)錯(cuò)誤進(jìn)行捕獲和處理,并不是所有的函數(shù)和方法都有這個(gè)必要性,有的是沒(méi)有這個(gè)必要性的,所以只能往上傳播給它的調(diào)用者。有的函數(shù)和方法是需要捕獲并處理的。
比如一些權(quán)限的問(wèn)題,有人有必要有能力來(lái)處理這個(gè)錯(cuò)誤,把錯(cuò)誤拋給他,他來(lái)處理。比如有些錯(cuò)誤是給用戶看的,有些是給管理員看的,如果是給用戶看的錯(cuò)誤要拋給表示層(view, viewController),如果是給系統(tǒng)管理員看的,直接打印日志,存到數(shù)據(jù)庫(kù)里,或發(fā)個(gè)郵件就可以了。
聲明拋出錯(cuò)誤
能放到try后面調(diào)用的函數(shù)或方法都是有要求的,它們是有可能拋出錯(cuò)誤,但你要在這些函數(shù)或方法聲明的參數(shù)后面加上throws關(guān)鍵字,表示這個(gè)函數(shù)或方法可以拋出錯(cuò)誤。
示例:
//刪除Note記錄的方法
func remove(model: Note) throws {
...
}
//查詢所有記錄數(shù)據(jù)的方法
func findAll() throws -> [Note] {
...
}
try? 和 try!的使用區(qū)別
1、使用try
try?會(huì)將錯(cuò)誤轉(zhuǎn)換為可選值,當(dāng)調(diào)用try? + 函數(shù)或方法語(yǔ)句時(shí),如果函數(shù)或方法拋出錯(cuò)誤,程序不會(huì)崩潰,而是返回一個(gè)nil; 如果沒(méi)有拋出錯(cuò)誤,則返回可選值。
func findAll() throws -> [Note] {
guard listData.count > 0 else {
//拋出“沒(méi)有數(shù)據(jù)”錯(cuò)誤
throw DAOError.NoData
}
return listData
}
let datas = try? findAll()
print(datas)
2、使用try!
使用try!可以打破錯(cuò)誤傳播鏈條。錯(cuò)誤拋出后被傳播者捕獲,這樣就形成了一個(gè)傳播鏈條,有時(shí)我們確實(shí)不想讓錯(cuò)誤傳播下去,這時(shí)便可以使用try!語(yǔ)句。
//查詢所有數(shù)據(jù)方法
func findAll() throws -> [Note] {
guard listData.count > 0 else {
//拋出“沒(méi)有數(shù)據(jù)”錯(cuò)誤
throw DAOError.NoData
}
return listData
}
func printNotes() {
let datas = try! findAll()
for note in datas {
print("data: \(note.date!) - content:\(note.content!)")
}
}
printNotes()