美文网首页
OneDayOneSwift[25] - Advanced Op

OneDayOneSwift[25] - Advanced Op

作者: OrangeInce | 来源:发表于2016-01-28 20:42 被阅读0次

    错误处理(Error handling)是响应错误以及从错误中恢复的过程。Swift 提供了在运行时对可恢复错误的抛出、捕获、传递和操作的一流支持。

    某些操作无法保证总是执行完所有代码或总是生成有用的结果。可选类型可用来表示值缺失,但是当某个操作失败时,最好能得知失败的原因,从而可以作出相应的应对。

    ps: Swift 中的错误处理涉及到错误处理模式,这会用到 Cocoa 和 Objective-C 中的NSError

    表示并抛出错误

    在 Swift 中,错误用符合ErrorType协议的类型的值来表示。这个空协议表明该类型可以用于错误处理。

    enum VendingMachineError: ErrorType {
        case InvalidSelection                    //选择无效
        case InsufficientFunds(coinsNeeded: Int) //金额不足
        case OutOfStock                          //缺货
    }
    
    throw VendingMachineError.InsufficientFunds(coinsNeeded: 5)
    

    处理错误

    Swift 中有4种处理错误的方式。

    • 把函数抛出的错误传递给调用此函数的代码
    • 用do-catch语句处理错误
    • 将错误作为可选类型处理
    • 断言此错误根本不会发生。

    ps: Swift 中的错误处理和其他语言中用trycatchthrow进行异常处理很像。和其他语言中(包括 Objective-C )的异常处理不同的是,Swift 中的错误处理并不涉及解除调用栈,这是一个计算代价高昂的过程。就此而言,throw语句的性能特性是可以和return语句相媲美的。

    用 throwing 函数传递错误

    为了表示一个函数、方法或构造器可以抛出错误,在函数声明的参数列表之后加上throws关键字。一个标有throws关键字的函数被称作 throwing 函数。

    func canThrowErrors() throws -> String
    func cannotThrowErrors() -> String
    

    一个 throwing 函数可以在其内部抛出错误,并将错误传递到函数被调用时的作用域。

    ps: 只有 throwing 函数可以传递错误。任何在某个非 throwing 函数内部抛出的错误只能在函数内部处理。

    用 Do-Catch 处理错误

    do {
        try expression
        statements
    } catch pattern 1 {
        statements
    } catch pattern 2 where condition {
        statements
    }
    

    catch子句不必将do子句中的代码所抛出的每一个可能的错误都作处理。如果所有catch子句都未处理错误,错误就会传递到周围的作用域。然而,错误还是必须要被某个周围的作用域处理的——要么是一个外围的do-catch错误处理语句,要么是一个 throwing 函数的内部。

    将错误转换成可选值

    可以使用try?通过将错误转换成一个可选值来处理错误。如果在评估try?表达式时一个错误被抛出,那么表达式的值就是nil。例如下面代码中的xy具有相同的值:

    
    func someThrowingFunction() throws -> Int {
        // ...
    }
    
    let x = try? someThrowingFunction()
    
    let y: Int?
    do {
        y = try someThrowingFunction()
    } catch {
        y = nil
    }
    

    如果你想对所有的错误都采用同样的方式来处理,用try?就可以让你写出简洁的错误处理代码。例如,下面的代码用几种方式来获取数据,如果所有方式都失败了则返回nil

    func fetchData() -> Data? {
        if let data = try? fetchDataFromDisk() { return data }
        if let data = try? fetchDataFromServer() { return data }
        return nil
    }
    

    禁用错误传递

    有时你知道某个 throwing 函数实际上在运行时是不会抛出错误的,在这种情况下,你可以在表达式前面写try!来禁用错误传递,这会把调用包装在一个断言不会有错误抛出的运行时断言中。如果实际上抛出了错误,你会得到一个运行时错误。

    例如,下面的代码使用了loadImage(_:)函数,该函数从给定的路径加载图片资源,如果图片无法载入则抛出一个错误。在这种情况下,因为图片是和应用绑定的,运行时不会有错误抛出,所以适合禁用错误传递:

    let photo = try! loadImage("./Resources/John Appleseed.jpg")
    

    指定清理操作

    可以使用defer语句在即将离开当前代码块时执行一系列语句。该语句让你能执行一些必要的清理工作,不管是以何种方式离开当前代码块的——无论是由于抛出错误而离开,还是由于诸如return或者break的语句。

    defer语句将代码的执行延迟到当前的作用域退出之前。该语句由defer关键字和要被延迟执行的语句组成。延迟执行的语句不能包含任何控制转移语句,例如break或是return语句,或是抛出一个错误。延迟执行的操作会按照它们被指定时的顺序的相反顺序执行——也就是说,第一条defer语句中的代码会在第二条defer语句中的代码被执行之后才执行,以此类推。

    ps: 即使没有涉及到错误处理,你也可以使用defer语句。

    func deferTestFun() {
        defer {
            print("first defer")
        }
        defer {
            print("second defer")
        }
        print("start test defer")
        return
    }
    
    //print: start test defer
    //print: second defer
    //print: first defer
    

    要点总结

    抛出的错误可以使用try?来消化。转成一个返回类型的可选类型。
    defer可以用来做一些善后操作

    相关文章

      网友评论

          本文标题:OneDayOneSwift[25] - Advanced Op

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