对于大部分现代化面向对象的编程语言都拥有结构化的错误处理语法特性,swift也不例外。当我们在一个方法或函数中实现某些功能时,如果遇到错误的用户输入则可能导致严重的异常问题,此时我们可以选择通过抛出异常的方式,将此错误送给函数调用者。
我们常用 try-catch 结构,不过在swift编程语言中没有引入专门的 try 语句块,而是直接调用之前的 do 语句块,仅仅将 try 作为抛出异常的函数或方法的标识,然后在 do 语句块后接 catch 语句块捕获错误并进行处理。
do {
let str = try String(contentsOfFile: "/Users/zennychen/Desktop/test.txt", encoding: String.Encoding.ascii)
print("content is: \(str)")
}
catch {
print("file read failed!")
}
第一节 swift中错误的表示
在 swift 中如果我们要定义一个表示错误的类型非常简单,只要遵循 Error 协议就可以了,我们通常用枚举或结构体来表示错误类型,枚举可能用的多些,因为它能更直观的表达当前错误类型的每种错误细节。
当我们定义了一个错误类型之后,可以实现 Error 协议中扩展默认实现的只读属性 localizedDescription,用于描述当前错误对象的详细信息
/// 定义一个枚举类型的错误类型
enum MyEnumError: Error {
case errorOne
case errorTwo
/// 实现Error协议的localizedDescription只读实例属性
var localizedDescription: String {
let desc = self == .errorOne ? "the first errror" : "the second error"
return "\(self): \(desc)"
}
}
/// 定义一个结构体类型的错误类型
struct MyStructError: Error {
var errCode: Int = 0
/// 实现Error协议的localizedDescription只读实例属性
var localizedDescription: String {
return "The error code is: \(errCode)"
}
}
print("The enum error is: \(MyEnumError.errorOne.localizedDescription)")
print("The struct error is: \(MyStructError().localizedDescription)")
第二节 swift中的错误抛出
如果我们在一个函数或方法中可能要抛出一个错误,那么我们必须在该函数的形参列表后面,返回类型前面(即 -> 前面)添加 throws 关键字,以显示告诉编译器,该函数可能会抛出错误。
/// 定义一个foo函数,
/// 它可能会抛出一个错误,
/// 因此这里用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对象,
// 并且其errCode的值为-1
throw MyStructError(errCode: -1)
}
print("a = \(a)")
return a
}
// ref的类型为:(Int) throws -> Void
let ref = foo(a:)
第三节 错误捕获与处理
在Swift 编程语言中我们使用 do-catch 块对错误进行捕获,当我们在调用一个 throws 声明的函数或方法时,我们必须把调用语句放在 do 语句块中,同时 do 语句块后面紧接着使用 catch 语句块。
当我们在 do 语句块中调用了一个可能会抛出错误的函数时,而此时该函数在执行时确实抛出了错误,我们在 catch 语句块汇总可以捕获错误并进行处理,一旦 do 语句块中抛出错误,接下来的代码将不会被执行,会跳到 catch 语句块中,catch 语句块中的代码执行完成后,其下面的代码也会执行,如果 do 语句块中无错误抛出,catch 语句块不会被执行。
// 由于在以下语句中包含了对可抛出错误的函数调用,
// 因此这里使用do语句块将这些调用围起来
do {
// 对于任一可能会抛出错误的函数,
// 在调用前面都必须添加try关键字
var value = try foo(a: -100)
value += try foo(a: 100)
value += try foo(a: 0)
print("value = \(value)")
} // 下面紧接着使用catch语句块
catch let err {
// 如果在do语句块中有任一错误抛出,
// 那么即会执行此catch语句块中的内容
print("err is: \(err)")
}
// 无论上面do语句块是否有错误,
// 这句打印均会执行
print("complete")