微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Swift(十八、错误处理)

1、Swift入门学习笔记(第一版),对Swift的基础知识点进行梳理总结。知识点一直在变,只是作为参考,以苹果官方文档为准~

2、在学习完基本的知识点以后会结合官方文档及相关资料,在此版本的基础上进行添加更改。

十八、错误处理

响应错误以及从错误中恢复的过程,在运行时可恢复错误抛出,捕获,传送和操作的高级支持

1、表示并抛出错误

错误遵循ErrorType协议的值来表示,可用枚举列出错误情景

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

使用throw关键字抛出

throw vendingMachineError.OutOfStock

2、处理错误

Swift提供四种方式:
a、把函数抛出的错误传递给调用函数代码

b、用do-catch语句处理错误

c、将错误作为可选类型处理

d、断言此错误根本不会发生

2.1、用throwing函数传递错误

函数参数列表之后,->之前加上throws

func canThrowsErrors() throws -> String

throwing函数从其内部抛出错误,并传递到该函数调用时所在的区域中

struct Item {
    var price:Int
    var count:Int
}

class vendingMachine {
    var inventory = [                           //存货清单
        "Candy Bar":Item(price: 12,count: 7),"Chips"    :Item(price: 10,count: 4),"Pretzels" :Item(price: 7,count: 11)   //椒盐卷饼
    ]

    var coinsDeposited = 0                      //存款
    func dispenseSnack(snack:String) {          //分配零食
        print("dispensing \(snack)")
    }

    func vend(itemNamed name:String) throws {
        guard var item = inventory[name] else {     //所需货物要在清单内否则抛出错误
            throw vendingMachineError.InvalidSelection
        }

        guard item.count > 0 else {                 //要有存货否则抛出错误
            throw vendingMachineError.OutOfStock
        }

        guard item.price <= coinsDeposited else {   //有足够的金钱购买否则抛出错误
            throw vendingMachineError.InsufficientFunds(coinsNeeded: item.price-coinsDeposited)
        }

        coinsDeposited -= item.price        //存款减去费用
        --item.count                        //存货减一
        inventory[name] = item
        dispenseSnack(name)                 //调函数说明正在分发物品
    }
}

根据上面的描述可看出,vend(itemNamed:)可能抛出错误

使用try传递,try后面跟可能发生错误的区域

定义属性

var vend = vendingMachine()
vend.coinsDeposited = 1
try vend.vend(itemNamed: "Chips")

Output:

错误处理.vendingMachineError.InsufficientFunds(9)
vend.coinsDeposited = 100
try vend.vend(itemNamed: "Chip")

Output:

错误处理.vendingMachineError.InvalidSelection

其他错误就不一一演示了~验证起来十分简单

2.2、用Do-Catch处理错误

这里的过程相当于将上面的错误提示用一段闭包来处理

var vend = vendingMachine() vend.coinsDeposited = 100
do {
    try vend.vend(itemNamed: "Chips")
} catch vendingMachineError.InvalidSelection {
    print("Invalid Selection.")
} catch vendingMachineError.OutOfStock {
    print("Out of Stock.")
} catch vendingMachineError.InsufficientFunds(let coinsNeeded) {
    print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
}

Output:

dispensing Chips

这是无异常的输出结果,可以尝试修改成其他结果验证

2.3、将错误转换为可选值

使用try?错误转换为一个可选值来处理错误

如果抛出错误,那么这个表达式为nil,否则,即正常情况就是函数的返回值

func someThrowingFunction() throws -> Int {
    // ...
}

let x = try? someThrowingFunction()

let y: Int?
do {
    y = try someThrowingFunction()
} catch {
    y = nil
}

但是不管正不正常,x、y都是可选类型

let result = try?vend.vend(itemNamed: "XXX")
print(result)       //结果是nil,因为货物不在清单中

Output:

nil

2.4、使错误传递失效

try?外还有try!处理错误情况,但是try!是确定没错的情况下值为函数返回值,如果出错直接崩溃。错误不会抛给catch处理或向上抛出

3、指定清理操作

defer语句,代码执行要离开当前代码段之前执行的一套语句。不管以何种方式离开(错误returnbreak等),都会去执行的一些必要的清理工作

defer关键字与要被延迟执行的语句组成
延迟执行操作是按照被指定的相反顺序执行的,譬如有两个defer语句,那么第一条defer在第二条defer执行之后执行

defer语句不一定在错误处理代码中使用,其他情况也常使用

这里的功能有点类似OC中异常处理机制中的finally关键字

func testDefer() throws {
    print("111111")
    defer {
        print("Defer1")
    }
    print("222222")
    defer {
        print("Defer2")
    }
    print("333333")

    do {
        defer {
            print("Do-Catch Defer")
        }

        try vend.vend(itemNamed: "chippppp")
    } catch vendingMachineError.InvalidSelection {
        print("Invalid Selection.")
    } catch vendingMachineError.OutOfStock {
        print("Out of Stock.")
    } catch vendingMachineError.InsufficientFunds(let coinsNeeded) {
        print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
    }

}
try testDefer()

Output:

111111
222222
333333
Do-Catch Defer
Invalid Selection.
Defer2
Defer1

注意打印顺序,尤其Do-Catch中的打印顺序,defer语句先于catch打印,可能defer离开代码段之前的意思可能是外层{ },不知道这样理解对不对

如果把do中的代码顺序换下

do {
    try vend.vend(itemNamed: "chippppp")
    defer {
        print("Do-Catch Defer")
    }
}

Output:

111111
222222
333333
Invalid Selection.
Defer2
Defer1

会发现dodefer语句根本没有执行,没有打印结果,这点在以后的应用中要注意

原文地址:https://www.jb51.cc/swift/325445.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐