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