do-try-catch错误处理模式
Swift2.x抛弃了cocoa的错误处理模式,使用了do-try-catch错误处理模式
cocoa的错误处理模式
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没有强制处理机制,因此一旦真的发生错误,程序就会崩溃。
do-try-catch错误模式
do {
let str = try NSString(contentsOfFile: filePath, encoding: NSUTF8StringEncoding)
} catch let err as NSError {
print(err.description)
}
注: do-tyr-catch这种错误模式与Java中异常处理机制非常类似,本意就是尝试( try )做一件事情,如果失败则捕获( catch )处理。
捕获错误
完整的do-try-catch错误处理模式语法如下:
do {
try 语句
成功处理语句组
} catch 匹配错误 {
错误处理语句组
}
错误类型
在Swift中错误类型必须遵从Error Type协议,其次是考虑错误类型的匹配,它应该设计为枚举类型,因为枚举类型非常适合将一组相关值关联起来。
enum DAOError: Error {
case NOData
case PrimaryKeyNull
}
do {
//try 访问数据表函数或方法
} catch DAOError.NOData {
print("没有数据。")
}catch DAOError.PrimaryKeyNull {
print("主键为空。")
}
在函数或方法中抛出错误
- 在函数或方法中通过throw语句人为地抛出错误
- 在函数或方法中调用其他可以抛出错误的函数或方法,但是没有捕获处理,会导致错误被传播出来。
//删除Note 方法
func remove(model: Note) throws {
guard let date = model.data else {
//抛出“主键为空”错误
throw DAOError.PrimaryKeyNull
}
//比较日期主键是否相等
for (index, note) in listData.enumerate() where note.date == date {
listData.removeIndex(index)
}
}
//查询所有数据方法
func findAll() throws -> [Note] {
guard listData.count > 0 else {
//抛出“没有数据”错误
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方法我们声明为有可能发生错误,加了个throws, 如果 let date = model.date 成立的话,走for语句,否则抛出异常“ throw DAOError.PrimaryKeyNull”,跳出程序代码。
2、findAll方法我们声明为有可能发生错误,加了个throws, 有返回值[Note],如果“listData.count > 0” 成立,返回listData,否则抛出异常。
3、printNotes方法我们声明为有可能发生错误,加了个throws。
方法内部调用findAll方法,即在printNotes方法中调用了可以抛出错误的findAll方法,所以前面要加try,但却没有用catch捕获处理这个错误,一旦发生错误,捕获不到错误,方法不会继续往下走,跳出方法,往下传播,传播它的上层调用者,把错误给上层调用者,上层调用者还是处理不了的话,在往下传,最后传到运行环境,然后崩溃。
4、调用“try printNotes()” ,会调用printNotes方法, 调用printNotes方法又会调用findAll方法,如果findAll方法中有错误发生的情况下,错误传递给findAll方法,findAll方法又会传递给printNotes方法,然后再传递给“try printNotes”。如果“try printNotes”也不捕获的话就会传递给运行环境,运行环境遇到错误后就会崩掉。
注:对错误进行捕获和处理,并不是所有的函数和方法都有这个必要性,有的是没有这个必要性的,所以只能往上传播给它的调用者。有的函数和方法是需要捕获并处理的。
比如一些权限的问题,有人有必要有能力来处理这个错误,把错误抛给他,他来处理。比如有些错误是给用户看的,有些是给管理员看的,如果是给用户看的错误要抛给表示层(view, viewController),如果是给系统管理员看的,直接打印日志,存到数据库里,或发个邮件就可以了。
声明抛出错误
能放到try后面调用的函数或方法都是有要求的,它们是有可能抛出错误,但你要在这些函数或方法声明的参数后面加上throws关键字,表示这个函数或方法可以抛出错误。
示例:
//删除Note记录的方法
func remove(model: Note) throws {
...
}
//查询所有记录数据的方法
func findAll() throws -> [Note] {
...
}
try? 和 try!的使用区别
1、使用try
try?会将错误转换为可选值,当调用try? + 函数或方法语句时,如果函数或方法抛出错误,程序不会崩溃,而是返回一个nil; 如果没有抛出错误,则返回可选值。
func findAll() throws -> [Note] {
guard listData.count > 0 else {
//抛出“没有数据”错误
throw DAOError.NoData
}
return listData
}
let datas = try? findAll()
print(datas)
2、使用try!
使用try!可以打破错误传播链条。错误抛出后被传播者捕获,这样就形成了一个传播链条,有时我们确实不想让错误传播下去,这时便可以使用try!语句。
//查询所有数据方法
func findAll() throws -> [Note] {
guard listData.count > 0 else {
//抛出“没有数据”错误
throw DAOError.NoData
}
return listData
}
func printNotes() {
let datas = try! findAll()
for note in datas {
print("data: \(note.date!) - content:\(note.content!)")
}
}
printNotes()