美文网首页
Swift - 错误处理(Error Handling)

Swift - 错误处理(Error Handling)

作者: iVikings | 来源:发表于2020-06-24 22:52 被阅读0次

    错误处理(Error Handling)

    错误类型

    • 语法错误(编译错误)
    • 逻辑错误
    • 运行时错误(可能会导致闪退,一般也叫做异常)
    • ......

    自定义错误

    • 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
    func test() {
        print(1)
        do {
            print(2)
            print(try divide(20, 0))
            print(3)
        } catch let SomeError.illegalArg(msg) {
            print("参数异常:", msg)
        } catch let SomeError.outOfBounds(size, index) {
            print("下标越界:", "size = \(size)", "index = \(index)")
        } catch SomeError.outOfMemory {
            print("内存溢出")
        } catch {
            print("其他错误")
        }
        print(4)
    }
    
    test()
    //1
    //2
    //参数异常: 0 不能作为除数
    //4
    
    do {
        print(try divide(20, 0))
    } catch let error {
        switch error {
        case let SomeError.illegalArg(msg):
            print("参数错误:", msg)
        default:
            print("其他错误")
        }
    }
    
    • 抛出 Error 后,try 下一句直到作用域结束的代码都将停止运行

    处理 Error

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

    func test() throws {
        print(1)
        print(try divide(20, 0))
        print(2)
    }
    try test()
    //1
    //Fatal error: Error raised at top level: practice.SomeError.illegalArg("0 不能作为除数"): file ...
    
    func test2() throws {
        print(1)
        do {
            print(2)
            print(try divide(20, 0))
            print(3)
        } catch let error as SomeError {
            print(error)
        }
        print(4)
    }
    try test2()
    //1
    //2
    //illegalArg("0 不能作为除数")
    //4
    

    try?、try!

    • 可以使用 try?try!调用可能会抛出 Error 的函数,这样就不用去处理 Error
    func test3() {
        print(try? divide(20, 10))
        print(try? divide(20, 0))
        print(try! divide(20, 10))
    }
    test3()
    //Optional(2)
    //nil
    //2
    
    • a、b 是等价的
    var a = try? divide(20, 0)
    var b: Int?
    do {
        b = try divide(20, 0)
    } catch {
        b = nil
    }
    

    rethrows

    • rethrows 表明:函数本身不会抛出错误,但调用闭包参数抛出错误,那么它会将错误向上抛
    func exex(_ fn: (Int, Int) throws -> Int, _ num1: Int, _ num2: Int) rethrows {
        print(try fn(num1, num2))
    }
    
    try exex(divide, 20, 0)
    // Fatal error: Error raised at top level: practice.SomeError.illegalArg("0 不能作为除数"): file ...
    

    defer

    • defer 语句:用来定义以任何方式(抛错误、return 等)离开代码块前必须要执行的代码
    • defer 语句将延迟至当前作用域结束之前执行
    func open(_ filename: String) -> Int {
        print("open")
        return 0
    }
    
    func close(_ file: Int) {
        print("close")
    }
    
    func processFile(_ filename: String) throws  {
        let file = open(filename)
        defer {
            close(file)
        }
        // 使用 file
        // ...
        try divide(20, 0)
        
        // close 将会在这里调用
    }
    
    try processFile("book.txt")
    
    //open
    //close
    //Fatal error: Error raised at top level: practice.SomeError.illegalArg("0 不能作为除数"): file ...
    

    assert(断言)

    • 很多编程语言都有断言机制:不符合指定条件就抛出运行时错误,常用于调试(Debug)阶段的条件判断
    • 默认情况下,Swift 的断言只会在 Debug 模式下生效,Release 模式下忽略
    func divide(_ v1: Int, _ v2: Int) -> Int {
        assert(v2 != 0, "除数不能为 0")
        return v1 / v2
    }
    
    print(divide(20, 0))
    // Assertion failed: 除数不能为 0: file 
    
    • 增加 Swift Flags 修改断言的默认行为
    • -assert-config Release:强制关闭断言
    • -assert-config Debug:强制开启断言
    Swift Flags

    fatalError

    • 如果遇到严重问题,希望结束程序运行时,可以直接使用 fatalError 函数抛出错误(这是无法通过 do-catch 捕捉的错误)
    • 使用了 fatalError 函数,就不需要再写 return
    func test(_ num: Int) -> Int {
        if num >= 0 {
            return 1
        }
        fatalError("num 不能小于 0")
    }
    
    • 在某些不得不实现、但不希望别人调用的方法,可以考虑内部使用 fatalError 函数
    class Person { required init() { } }
    class Student: Person {
        required init() {
            fatalError("don't call Student.init")
        }
        init(score: Int) { }
    }
    
    var stu1 = Student(score: 99)
    var stu2 = Student() // Fatal error: don't call Student.init
    

    局部作用域

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

    相关文章

      网友评论

          本文标题:Swift - 错误处理(Error Handling)

          本文链接:https://www.haomeiwen.com/subject/poadfktx.html