美文网首页js css html
Swift 异常处理

Swift 异常处理

作者: 你duck不必呀 | 来源:发表于2022-07-11 10:24 被阅读0次

    为了减少程序运行中产生异常,就需要一套异常处理机制
    那些常规错误,例如网络请求错误。这些错误,在编写代码的时候尽可能去避免就好。那些预料之外的错误,比如,数组越界,range边界,除数不能是0等,就要用到异常处理机制。
    在swift中在发生异常的位置添加如下几种代码,可以通过下面几种方式处理错误:

    assertpreconditionfatalError.

    assert 只在Debug环境下生效
    precondition 在Debug和生产阶段都都生效
    fatalError 抛出异常,无法捕获

    这几种方式发生异常都能定位到具体的行,缺点是不能再恢复执行(也就是闪退)

    swift的错误处理机制

    Error协议

    Error协议本身没有内容,遵守这个Error协议,就可以将错误抛出和捕获,而且任何自定义的类型都可以遵守此Error协议。

    看一个官方文档中的例子:

    从字符串解析整数时可能发生的两种不同类型的错误:

    enum IntParsingError: Error {
        case overflow // 溢出
        case invalidInput(Character) //包含无效的字符
    }
    // 扩展 Int类型 ,
    extension Int {
        init(validating input: String) throws {
            // ...
            let c = _nextCharacter(from: input)
            if !_isValid(c) {
                throw IntParsingError.invalidInput(c)
            }
        }
    }
    
    // 解析字符串,通过 do-catch
    do {
        let price = try Int(validating: "$100")
    } catch IntParsingError.invalidInput(let invalid) {
        print("Invalid character: '\(invalid)'")
    } catch IntParsingError.overflow {
        print("Overflow error")
    } catch {
        print("Other error")
    }
    // Prints "Invalid character: '$'"
    
    

    throws
    throws用来标记一个方法,该方法会在失败时抛出异常

    // 无返回值
    func initWithValidating(from:String) throws
    // 有返回值
    func initWithValidating(from:String) throws -> Int
    

    完整的定义如下:

    // 传入一个字符串,返回该字符串的Int类型
    func initWithValidating(from:String) throws -> Int {
        // ...
        let c = _nextCharacter(from)
        if !_isValid(c) {
            throw IntParsingError.invalidInput(c)
        }
        return Int(from)
    }
    

    被标记为throws的API必须通过完整的 try catch 来捕获可能的异常,否则无法编译通过:

    do{
        let result = try initWithValidating(from:"$100")
        // do...
    }catch{
        //  throw抛出异常会来到这里       
    }
    

    或者带有更具体的错误信息

    do{
        let result = try initWithValidating(from:"$100")
        // do...
    } catch IntParsingError.invalidInput(let invalid) {
        print("Invalid character: '\(invalid)'")
    } catch IntParsingError.overflow {
        print("Overflow error")
    } catch {
        // 虽然两种情况都考虑到了,但是编译器要求必须加上默认的catch块
        // 编译器自动生成的error变量
        print("Other \(error)")
    }
    

    rethrows

    继续上面的例子,我们现在需要对返回的整数做一下格式化,输出如下效果:

    输入:10000000000
    输出:10,000,000,000
    

    下面这个函数可以对转换后的数字格式化:

    func formatNum(from:String,v:(String) throws -> Int) throws {
        
        do{
            let num = try v(from)
            let format = NumberFormatter()
            format.numberStyle = .decimal
            if let result = format.string(from: NSNumber(value: num)){
                print(result)
            }
        }catch{
            throw error
        }
    }
    

    现在使用这个新的方法formatNum,参数v可以传入上面的initWithValidating并且传入"10000000000"作为第一个参数,编译器会提示我们必须加上 try 来处理可能发生的异常,但是很明显这个数字不会发生异常。

    typealias verify = (String) throws -> Int
    
    var validating:verify = { from in
        for i in from where !i.isNumber{
            throw "Error:'\(i)' not a number!"
        }
        return Int(from)!
    }
    // 编译器会提示我们必须加上 try 来处理可能发生的异常
    try formatNum(from: "10000000000", v: validating)
    

    现在把formatNum后面的throws标记改成rethrows,并且传入一个不会抛出异常的参数v,这个时候编译器不再提示我们必须加上 try 来处理可能发生的异常,编译也正常通过

    var noErrorValidating:(String)->Int = { from in
        return Int(from)!
    }
    formatNum(from: "10000000000", v: noErrorValidating)
    // 输出:10,000,000,000
    
    

    乍一看好像没什么用,只是省略了try来捕获异常。
    其实,Swift标准库提供的map函数也是这么实现的,当我map一个序列,后面传入的transform不带抛出异常的时候我们不需要前面的try

    @inlinable public func map<T>(_ transform: (Character) throws -> T) rethrows -> [T]
    

    rethrows 关键字用于本身不抛出错误,而是转发包含抛出错误的函数类型参数(闭包参数)。同时提供一个便利,仅在函数参数抛出错误时需要try关键字。

    do/catch

    调用一个可抛出错误的函数,编译器会迫使我们决定如何处理错误。
    使用 do/catch 直接处理,可能会存在多条 catch 语句,可以用模式匹配来捕获某个特定的错误类型,见上文的例子:
    错误转换

    try try? try!
    try用于 throws 和 Optionals 之间转换

    try 用在do/catch中,或者转移错误
    try? 返回一个可选值,并且忽略错误信息,发生错误时返回 nil
    try! 返回一个可选值并且强制解包,发生错误时会crash

    相关文章

      网友评论

        本文标题:Swift 异常处理

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