其他分享
首页 > 其他分享> > swift 异常处理

swift 异常处理

作者:互联网

一、错误类型

1、正常的错误类型通过枚举的方式来定义(通过实现协议Error,但是Error协议进去发现是空的?)

enum VendingMachineError: Error {
    case invalidSelection
    case outOfStock
    case insufficientFunds(coinsNeeded: Int)
}

这里自定义了3种类型,第三种的insufficientFunds额外增加了参数的设置,用来抛出错误时候额外增加的错误信息

 

二、错误的抛出

1、错误是通过throw关键字抛出,注意throw后面没有s

        guard let 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)
        }

如上所示,抛出了1中的自定义的各个类型;其中VendingMachineError.insufficientFunds 增加了额外的缺多少钱的信息;在实际应用中可以增加更多的参数和其他需要的异常信息

 

2、错误的抛出是通过在函数后面增加throws,如下所示

    func vend(itemNamed name: String) throws {
        guard let 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)
        }

        。。。。。。。
    }

如上标志红色的所示,如果函数中有throw,则需要在函数的列表右括号紧接着throws标志该函数可能会抛出异常(注意这里的throw后面加s)

如果函数要有返回值的话那么要写在throws的后面,比如上面的vend函数要返回String可以如下所示,在throws的后面增加返回String

func vend(itemNamed name: String) throws -> String {
......
}

 

3、闭包的错误抛出跟2的规则差不多是一样的

lazy var blockVend: (_ name: String) throws -> String

如上所示,声明的类型跟普通的函数一样。

 

三、错误的捕获

1、函数可能会抛出异常,那么在执行该函数的时候,前面要增加try

try vendingMachine.vend(itemNamed: snackName)

那么如果有返回值的话

let ret = try vendingMachine.vend(itemNamed: snackName)

注意,此时如果vend函数抛出了异常,则try会继续向外部抛出vend抛出的异常。那么如果不想让vend抛出的异常再向外抛出的话,有两种方法可以阻止

1、在try后面增加问号

    let ret = try? vendingMachine.vend(itemNamed: snackName)
    print(ret)

此时,如果vend抛出异常,则不会再向外抛出异常,ret也有返回值(返回值是nil,因为vend因为异常被抛出了,则正常函数执行的返回代码未执行到所以为空)

2、使用do{}catch的方式

func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
    let snackName = favoriteSnacks[person] ?? "Candy Bar"
    let ret = try vendingMachine.vend(itemNamed: snackName)
    print(ret)
}
var vendingMachine = VendingMachine()

do {
    try buyFavoriteSnack(person: "kkqqq", vendingMachine: vendingMachine)
} catch VendingMachineError.invalidSelection {
    print("invalid selection")
} catch VendingMachineError.outOfStock {
    print("out of stock")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {
    print("insufficient \(coinsNeeded)")
} catch {
    print("\(error)")
}

如上所示,通过catch捕获各种类型的错误。并在最后的一个catch 不标明任何的类型即捕获任何到达这里的异常,并且error 是异常的类型

如果多个异常的类型要做相同的处理可以把他们合到一起

do {
    try buyFavoriteSnack(person: "kkqqq", vendingMachine: vendingMachine)
} catch VendingMachineError.invalidSelection, VendingMachineError.outOfStock {
    print("invalid selection")
}

如上所示多个异常用逗号隔开

也可以使用条件语句进行判断

catch VendingMachineError.insufficientFunds(let coinsNeeded) where coinsNeeded > 10 {
    print("insufficient \(coinsNeeded)")
}


catch is VendingMachineError {
        print("Couldn't buy that from the vending machine.")
    }

如上列举了两种条件的判断类型,还有其他的条件判断均是可以的

 

3、如果错误不想再继续抛出,并且要在错误抛出的位置直接显示异常

比如上面的例子buyFavoriteSnack函数的列表末尾有throws

func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {

这里如果打算让vend如果有异常让程序直接停止不再向外传递,那么throws则不加在buyFavoriteSnack的末尾。但是这样子的话程序编译不通过

这里有个处理方式是在try后面加感叹号!,如下所示

func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) {
    let snackName = favoriteSnacks[person] ?? "Candy Bar"
    let ret = try! vendingMachine.vend(itemNamed: snackName)
    print(ret)
}

 

四、类似java中的finally,在本block执行完毕时一定会执行的代码

我们有时会有这么个需求

1、一个函数中有多个return,并且return之前要清理某些资源,如果每个return的地方都写一次的话,那么代码的重复度就会很高

2、当函数中的异常抛出时,有些需要清理的资源还没来得及清理

swift为我们提供了一个关键字defer,当程序在离开本block的时候一定会执行defer中的代码

func processFile(filename: String) throws {
    if exists(filename) {
        let file = open(filename)
        defer {
            close(file)
        }
        while let line = try file.readline() {
            // Work with the file.
        }
        // close(file) is called here, at the end of the scope.
    }
}

如上的例子来源https://www.cnswift.org/error-handling

在if执行完毕之后会自动执行defer中的close(file)

标签:vendingMachine,处理,抛出,try,vend,swift,let,异常,VendingMachineError
来源: https://www.cnblogs.com/czwlinux/p/16315871.html