错误类型
开发中常见的错误:
语法错误(编译报错)
逻辑错误
运行时错误(可能会导致闪退,一般也叫做异常)
… …
自定义错误
Swift中可以通过Error协议自定义运行时的错误信息
enum MyError : Error {
case outOfBounds(Int)
case outOfMemory
case other(String)
}
函数内部通过throw抛出自定义Error,可能会抛出Error的函数必须加上throws声明
func test(num: Int) throws -> Int {
if num <= 0 {
throw MyError.other("参数有误")
}
return num
}
需要使用try调用可能会抛出Error的函数
try test(num: 0)
do-catch
可以用do-cathc捕捉Error
func doCatchTest() {
print("1")
do {
print("2")
try test(num: 0)
print("3")
} catch let MyError.outOfBounds(index) {
print("下标越界", index)
} catch MyError.outOfMemory {
print("内存溢出")
} catch let MyError.other(msg){
print("其他错误", msg)
} catch {
print("未知错误")
}
print("4")
}
doCatchTest()
打印结果:
1
2
其他错误 参数有误
4
抛出Error后,try下一句知道作用域结束的代码都将停止运行
处理Error
处理Error的2中方式
1、通过do-catch捕捉Error
2、不捕捉Error,在当前函数增加throws声明,Error将自动抛给上层函数,如果最顶层函数(main函数)依然没有捕捉Error,那么程序将终止
func test1() throws {
try test(num: 0)
}
func test2() throws {
try test1()
}
try test2()
test1函数没有捕获Error,则会抛给test2,test2也没有处理,所以会抛给main函数。
捕获Error时,判断Error类别方法一,通过转换类型判断
func doCatchTest() {
print("1")
do {
print("2")
try test(num: 0)
print("3")
} catch let error as MyError {
print("is my error", error)
} catch {
print("Other Error")
}
print("4")
}
方法二,通过is判断
func doCatchTest() {
print("1")
do {
print("2")
try test(num: 0)
print("3")
} catch is MyError {
print("is my error")
} catch {
print("Other Error")
}
print("4")
}
try?、try!
可以使用try?、try!调用可能会抛出Error的函数,这样就不用去处理Error
func tryTest() {
print("1")
try? test(num: 1)
try? test(num: 0)
try! test(num: 2)
print("2")
}
tryTest()
*try!是隐式解包,可能会造成崩溃
下方代码中a和b等价
var a = try? test(num: 1)
var b: Int?
do {
b = try test(num: 1)
} catch { b = nil }
rethrows
rethrows表明:函数本身不会抛出错误,但调用闭包参数抛出错误,那么它会将错误上抛
func test(_ num1: Int, _ num2: Int) throws -> Int {
if num1 < num2 {
throw MyError.other("其他错误")
}
return 0
}
func exec(_ fn: (Int, Int) throws -> Int, _ num1: Int, _ num2: Int) rethrows {
print(try fn(num1, num2))
}
try exec(test, 15, 20)
defer
defer语句:用来定义以任何方式(抛错误、return等)离开代码块前必须要执行的代码
// 需求:在执行文件中,无论成功还是失败,都需要关闭文件。
func open(_ filePath: String) -> Int {
print("open")
return 0
}
func close(_ fileId: Int) {
print("close")
}
func processFile(_ filePath: String) throws {
// 打开文件
let fileId = open(filePath)
defer {
close(fileId)
}
// 使用file ...
try test(num: 0)
// close将会在这里调用
}
defer的执行顺序与定义顺序相反
func fn1() {print(1)}
func fn2() {print(2)}
func fn3() {print(3)}
func fn() {
defer { fn1() }
defer { fn2() }
defer { fn3() }
}
fn()
打印结果:
3
2
1