Swift(十八、错误处理)

前端之家收集整理的这篇文章主要介绍了Swift(十八、错误处理)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

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

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


十八、错误处理


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


1、表示并抛出错误

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

  1. enum VendingMachineError: ErrorType {
  2. case InvalidSelection //选择无效
  3. case InsufficientFunds(coinsNeeded: Int) //金额不足
  4. case OutOfStock //缺货
  5. }

使用throw关键字抛出

  1. throw VendingMachineError.OutOfStock

2、处理错误

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

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

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

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


2.1、用throwing函数传递错误

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

  1. func canThrowsErrors() throws -> String

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


  1. struct Item {
  2. var price:Int
  3. var count:Int
  4. }
  5.  
  6. class VendingMachine {
  7. var inventory = [ //存货清单
  8. "Candy Bar":Item(price: 12,count: 7),"Chips" :Item(price: 10,count: 4),"Pretzels" :Item(price: 7,count: 11) //椒盐卷饼
  9. ]
  10.  
  11. var coinsDeposited = 0 //存款
  12. func dispenseSnack(snack:String) { //分配零食
  13. print("Dispensing \(snack)")
  14. }
  15.  
  16. func vend(itemNamed name:String) throws {
  17. guard var item = inventory[name] else { //所需货物要在清单内否则抛出错误
  18. throw VendingMachineError.InvalidSelection
  19. }
  20.  
  21. guard item.count > 0 else { //要有存货否则抛出错误
  22. throw VendingMachineError.OutOfStock
  23. }
  24.  
  25. guard item.price <= coinsDeposited else { //有足够的金钱购买否则抛出错误
  26. throw VendingMachineError.InsufficientFunds(coinsNeeded: item.price-coinsDeposited)
  27. }
  28.  
  29. coinsDeposited -= item.price //存款减去费用
  30. --item.count //存货减一
  31. inventory[name] = item
  32. dispenseSnack(name) //调函数说明正在分发物品
  33. }
  34. }

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

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

定义属性

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

Output:

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

Output:

  1. 错误处理.VendingMachineError.InvalidSelection

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


2.2、用Do-Catch处理错误

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

  1. var vend = VendingMachine() vend.coinsDeposited = 100
  1. do {
  2. try vend.vend(itemNamed: "Chips")
  3. } catch VendingMachineError.InvalidSelection {
  4. print("Invalid Selection.")
  5. } catch VendingMachineError.OutOfStock {
  6. print("Out of Stock.")
  7. } catch VendingMachineError.InsufficientFunds(let coinsNeeded) {
  8. print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
  9. }

Output:

  1. Dispensing Chips

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


2.3、将错误转换为可选值

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

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

  1. func someThrowingFunction() throws -> Int {
  2. // ...
  3. }
  4.  
  5. let x = try? someThrowingFunction()
  6.  
  7. let y: Int?
  8. do {
  9. y = try someThrowingFunction()
  10. } catch {
  11. y = nil
  12. }

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

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

Output:

  1. nil

2.4、使错误传递失效

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


3、指定清理操作

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

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

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

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

  1. func testDefer() throws {
  2. print("111111")
  3. defer {
  4. print("Defer1")
  5. }
  6. print("222222")
  7. defer {
  8. print("Defer2")
  9. }
  10. print("333333")
  11.  
  12. do {
  13. defer {
  14. print("Do-Catch Defer")
  15. }
  16.  
  17. try vend.vend(itemNamed: "chippppp")
  18. } catch VendingMachineError.InvalidSelection {
  19. print("Invalid Selection.")
  20. } catch VendingMachineError.OutOfStock {
  21. print("Out of Stock.")
  22. } catch VendingMachineError.InsufficientFunds(let coinsNeeded) {
  23. print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
  24. }
  25.  
  26. }
  27. try testDefer()

Output:

  1. 111111
  2. 222222
  3. 333333
  4. Do-Catch Defer
  5. Invalid Selection.
  6. Defer2
  7. Defer1

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

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

  1. do {
  2. try vend.vend(itemNamed: "chippppp")
  3. defer {
  4. print("Do-Catch Defer")
  5. }
  6. }

Output:

  1. 111111
  2. 222222
  3. 333333
  4. Invalid Selection.
  5. Defer2
  6. Defer1

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

猜你在找的Swift相关文章