Swift(十八、错误处理)

来源:互联网 发布:苹果手机网络无法连接 编辑:程序博客网 时间:2024/05/22 12:00

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 = 1try 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:

111111222222333333Do-Catch DeferInvalid Selection.Defer2Defer1

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

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

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

Output:

111111222222333333Invalid Selection.Defer2Defer1

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

0 0