错误类型

开发中常见的错误:
语法错误(编译报错)
逻辑错误
运行时错误(可能会导致闪退,一般也叫做异常)
… …

自定义错误

Swift中可以通过Error协议自定义运行时的错误信息

  1. enum MyError : Error {
  2. case outOfBounds(Int)
  3. case outOfMemory
  4. case other(String)
  5. }

函数内部通过throw抛出自定义Error,可能会抛出Error的函数必须加上throws声明

  1. func test(num: Int) throws -> Int {
  2. if num <= 0 {
  3. throw MyError.other("参数有误")
  4. }
  5. return num
  6. }

需要使用try调用可能会抛出Error的函数

  1. try test(num: 0)

do-catch

可以用do-cathc捕捉Error

  1. func doCatchTest() {
  2. print("1")
  3. do {
  4. print("2")
  5. try test(num: 0)
  6. print("3")
  7. } catch let MyError.outOfBounds(index) {
  8. print("下标越界", index)
  9. } catch MyError.outOfMemory {
  10. print("内存溢出")
  11. } catch let MyError.other(msg){
  12. print("其他错误", msg)
  13. } catch {
  14. print("未知错误")
  15. }
  16. print("4")
  17. }
  18. doCatchTest()

打印结果:

  1. 1
  2. 2
  3. 其他错误 参数有误
  4. 4

抛出Error后,try下一句知道作用域结束的代码都将停止运行

处理Error

处理Error的2中方式
1、通过do-catch捕捉Error
2、不捕捉Error,在当前函数增加throws声明,Error将自动抛给上层函数,如果最顶层函数(main函数)依然没有捕捉Error,那么程序将终止

  1. func test1() throws {
  2. try test(num: 0)
  3. }
  4. func test2() throws {
  5. try test1()
  6. }
  7. try test2()

test1函数没有捕获Error,则会抛给test2,test2也没有处理,所以会抛给main函数。
捕获Error时,判断Error类别方法一,通过转换类型判断

  1. func doCatchTest() {
  2. print("1")
  3. do {
  4. print("2")
  5. try test(num: 0)
  6. print("3")
  7. } catch let error as MyError {
  8. print("is my error", error)
  9. } catch {
  10. print("Other Error")
  11. }
  12. print("4")
  13. }

方法二,通过is判断

  1. func doCatchTest() {
  2. print("1")
  3. do {
  4. print("2")
  5. try test(num: 0)
  6. print("3")
  7. } catch is MyError {
  8. print("is my error")
  9. } catch {
  10. print("Other Error")
  11. }
  12. print("4")
  13. }

try?、try!

可以使用try?、try!调用可能会抛出Error的函数,这样就不用去处理Error

  1. func tryTest() {
  2. print("1")
  3. try? test(num: 1)
  4. try? test(num: 0)
  5. try! test(num: 2)
  6. print("2")
  7. }
  8. tryTest()

*try!是隐式解包,可能会造成崩溃

下方代码中a和b等价

  1. var a = try? test(num: 1)
  2. var b: Int?
  3. do {
  4. b = try test(num: 1)
  5. } catch { b = nil }

rethrows

rethrows表明:函数本身不会抛出错误,但调用闭包参数抛出错误,那么它会将错误上抛

  1. func test(_ num1: Int, _ num2: Int) throws -> Int {
  2. if num1 < num2 {
  3. throw MyError.other("其他错误")
  4. }
  5. return 0
  6. }
  7. func exec(_ fn: (Int, Int) throws -> Int, _ num1: Int, _ num2: Int) rethrows {
  8. print(try fn(num1, num2))
  9. }
  10. try exec(test, 15, 20)

defer

defer语句:用来定义以任何方式(抛错误、return等)离开代码块前必须要执行的代码

  1. // 需求:在执行文件中,无论成功还是失败,都需要关闭文件。
  2. func open(_ filePath: String) -> Int {
  3. print("open")
  4. return 0
  5. }
  6. func close(_ fileId: Int) {
  7. print("close")
  8. }
  9. func processFile(_ filePath: String) throws {
  10. // 打开文件
  11. let fileId = open(filePath)
  12. defer {
  13. close(fileId)
  14. }
  15. // 使用file ...
  16. try test(num: 0)
  17. // close将会在这里调用
  18. }

defer的执行顺序与定义顺序相反

  1. func fn1() {print(1)}
  2. func fn2() {print(2)}
  3. func fn3() {print(3)}
  4. func fn() {
  5. defer { fn1() }
  6. defer { fn2() }
  7. defer { fn3() }
  8. }
  9. fn()

打印结果:

  1. 3
  2. 2
  3. 1