Swift基础知识之错误处理

一、开发过程中常见的错误

  • 语法错误(编译报错)
  • 逻辑错误
  • 运行时错误(可能会导致闪退)
  • ...

二、自定义错误

  • Swift中可以通过Error协议自定义运行时的错误
enum SomeError : Error {
    case illegalArg(String)
    case outOfBounds(Int, Int)
    case outOfMemory
}
  • 函数内部可以通过throw抛出自定义Error,可能会抛出Error的函数必须加上throws声明
func divide(_ num1: Int, _ num2: Int) throws -> Int {
    if num2 == 0 {
        throw SomeError.illegalArg("0 不能作为除数")
    }
    return num1 / num2
}
  • 需要使用try调用可能会抛出Error的函数
var result = try divide(20, 10)

三、do-catch

  • 可以使用do-catch捕捉Error
  • 抛出Error后,try下一句知道作用域结束的代码都将停止运行
do {
    try divide(20, 0)
} catch let error {
    switch error {
    case let SomeError.illegalArg(msg):
        print("参数错误:", msg)
    default:
        print("其他错误")
    }
}

四、处理Error

  • 处理Error的两种方式
    • 通过do-catch捕捉Error
    • 不捕捉Error,在当前函数增加throws声明,Error将自动抛给上次函数
    • 如果最顶层函数(main函数)依然没有捕捉Error,那么程序将终止
func test() throws {
    print("1")
    print(try divide(20, 0))
    print("1")
}

五、try?、try!

  • 可以使用try?、try!调用可能会抛出Error的函数,这样就不用去处理Error
  • try? 如果调用的结果无错误、会将结果包装成一个可选项
  • try? 如果调用的结果有错误、会返回nil
  • try! 如果调用的结果无错误、会返回解包后的值
  • try! 如果有错误,程序终止error: Execution was interrupted, reason: EXC_BREAKPOINT
func test() {
    print("1 = ")
    print(try? divide(20, 10)) // Optional(2)
    print(try? divide(20, 0)) // nil
    print(try! divide(20, 20)) // 1
}
test()

// a、b是等价的
var a = try? divide(20, 0)
var b: Int?
do {
    b = try divide(20, 0)
} catch { b = nil }

六、rethrows

  • rethrows表明:函数本身不会抛出错误,但是调用闭包参数抛出错误,那么它将错误向上抛
func exec(_ fn: (Int, Int) throws -> Int, _ num1: Int, _ num2: Int) rethrows {
    print(try fn(num1, num2))
}

七、defer

  • defer语句:用来定义以任何方式(抛错误、return等)离开代码前必须执行的代码
  • defer语句将延迟至当前作用域结束之前执行
  • defer语句的执行顺序和定义顺序相反
func fn1() {print("fn1")}
func fn2() {print("fn2")}
func tests() {
    defer { fn1() }
    defer { fn2() }
}
tests() // fn2 fn1

八、assert (断言)

  • 不符合指定条件就抛出运行时错误,常用语调试(Debug)阶段的条件判断
  • 默认情况下、swift的断言智慧在Debug模式下生效、Release模式下会忽略
func divide(_ num1: Int, _ num2: Int) throws -> Int {
    assert(num2 != 0, "0 不能作为除数")
    return num1 / num2
}
  • 增加Swift Flags修改断言的默认行为
  • -assert-config Release : 强制关闭断言
  • -assert-config Debug : 强制开启断言

九、fatalError

  • 如果遇到验证问题,希望结束程序时,可以直接调用fatalError函数抛出错误(这里无法通过do-catch捕捉的错误)
  • 使用了fatalError函数,就不需要再写return
func test(_ num: Int) -> Int {
  if num >= 0 {
    return 1
  }
  fatalError("num 不能小于0")
}
  • 在默写不得不实现,但是不希望别人调用的方法,可以考虑内部使用fatalError函数

十、局部作用域

  • 可以使用do实现局部作用域
do {
    var dog = Dog()
    dog.run()
}
do {
    var dog = Dog()
    dog.run()
}

你可能感兴趣的:(Swift基础知识之错误处理)