• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Swift从入门到精通第十四篇 - 错误处理 初识

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

错误处理(学习笔记)

环境Xcode 11.0 beta4 swift 5.1

  • 错误表现和抛出
    • swift 中,错误由符合 Error 协议的类型值表示

      // 示例
      enum VendingMachineError: Error {
          case invalidSelection
          case insufficientFunds(coinsNeeded: Int)
          case outOfStock
      }
      // 抛出错误
      throw VendingMachineError.insufficientFunds(coinsNeeded: 5)
  • 错误处理
    • 在 Swift 中有四种处理错误的方式:一、从函数中把错误传递出来;二、用 do-catch 语句;三、作为可选值处理;四、用断言
    • 在 Swift 中错误处理与其它语言(包括OC)的异常类似,Swift 中错误处理不会涉及展开堆栈的调用,而堆栈的调用消耗是很大的,从性能的角度出发 throw 语句的性能与 return 性能是一样的
    • 函数抛出错误,只有声明了 throws 的函数才能往外抛出错误,如果不是则抛出的错误必须在函数内部处理

      func canThrowErrors() throws -> String
      // 
      func cannotThrowErrors() -> String
    • 示例代码

      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 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)
              }
              // 
              coinsDeposited -= item.price
              //
              var newItem = item
              newItem.count -= 1
              inventory[name] = newItem
              // 
              print("Dispensing \(name)")
          }
      }
      let favoriteSnacks = [
          "Alice": "Chips",
          "Bob": "Licorice",
          "Eve": "Pretzels",
      ]
      func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
          let snackName = favoriteSnacks[person] ?? "Candy Bar"
          try vendingMachine.vend(itemNamed: snackName) // 如果这里有错误,将会向外层抛
      }
    • 可抛出的初始化器也可以向外抛出错误

      struct PurchasedSnack {
          let name: String
          init(name: String, vendingMachine: VendingMachine) throws {
              try vendingMachine.vend(itemNamed: name)
              self.name = name
          }
      }
    • do-catch 处理错误,一般格式如下

      do {
          try expression
          // statements
      } catch pattern1 {
          // statements
      } catch pattern2 where condition {
          // statements
      } catch {
          // statements
      }
      // catch 后的 pattern1 表示这个大括号内处理 pattern1 类型的错误,如果省略不写表示处理任何类型的错误且把错误绑定到一个常量 `error`
      var vendingMachine = VendingMachine()
      vendingMachine.coinsDeposited = 8
      do {
          try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
          print("Success! Yum.")
      } 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.")
      } catch {
          print("Unexpected error: \(error).")
      }
      // Prints "Insufficient funds. Please insert an additional 2 coins."
    • 将错误转换为可选值
      • 可以用 try? 将错误转换为可选值,如果有错误抛出,计算 try? 表达式的值为 nil
        swift func someThrowingFunction() throws -> Int { // .... } let x = try? someThrowingFunction() let y: Int? do { y = try someThrowingFunction() }catch { y = nil } // 如果函数 someThrowingFunction 抛出错误,则 x 的值为 nil;否则 x、y 就是函数返回的值,且此时x、y是可选值
      • 如果想用 try? 准确处理所有错误,如下示例
        swift func fetchData() -> Data? { if let data = try? fecthDataFromDisk() { return data } if let data = try? fetchDataFromDisk() { return data } return nil }
    • 禁止错误传递,可以用 try! , 如果值是 nil,则会抛出运行时错误
    // 示例
    let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
  • 指定清理行为
    • 在当前代码块结束之前,可以用 defer 语句执行一组语句,做任何必需的清理操作,语句的执行无关是抛出错误或者是 return break 关键字之类
    • 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.
          }
      }

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Swift从入门到精通第十一篇 - 初始化 初识发布时间:2022-07-14
下一篇:
Swift从入门到精通第十五篇 - 类型转换 初识发布时间:2022-07-14
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap