错误处理(学习笔记)

环境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
        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? 准确处理所有错误,如下示例
        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.
      }
      }

Swift从入门到精通第十四篇 - 错误处理 初识的更多相关文章

  1. Swift从入门到精通第十五篇 - 类型转换 初识

    类型转换(学习笔记) 环境Xcode 11.0 beta4 swift 5.1 类型转换 类型转换是检查实例类型的一种方法,或者检查来自类层级不同的父类或子类一个实例,用 is 和 as 操作符 为类 ...

  2. Egret入门学习日记 --- 第十四篇(书中 5.4~5.6节 内容)

    第十四篇(书中 5.4~5.6节 内容) 书中内容: 总结 5.4节 内容重点: 1.如何编写自定义组件? 跟着做: 重点1:如何编写自定义组件? 文中提到了重要的两点. 好,我们来试试看. 第一步, ...

  3. Scala入门到精通——第二十四节 高级类型 (三)

    作者:摆摆少年梦 视频地址:http://blog.csdn.net/wsscy2004/article/details/38440247 本节主要内容 Type Specialization Man ...

  4. Simulink仿真入门到精通(十四) Simulink自定义环境

    14.1 Simulink环境自定义功能 sl_sustomization.m函数是Simulink提供给用户使用MATLAB语言自定义Simulink标准人机界面的函数机制.若sl_sustomiz ...

  5. Simulink仿真入门到精通(十九) 总结回顾&自我练习

    从2019年12月27到2020年2月12日,学习了Simulink仿真及代码生成技术入门到精通,历时17天. 学习的比较粗糙,有一些地方还没理解透彻,全书梳理总结: Simulink的基础模块已基本 ...

  6. Swift从入门到精通第十一篇 - 初始化 初识

    初始化(学习笔记) 环境Xcode 11.0 beta4 swift 5.1 初始化 初始化是类.结构体.枚举生成实例的过程,为该类的每个存储属性设置初始值,有些在实例使用前的设置或初始化也可在此实现 ...

  7. Swift从入门到精通第八篇 - 方法 初识

    方法(学习笔记) 环境Xcode 11.0 beta4 swift 5.1 方法 结构体.枚举.类都可以定义方法(实例方法.类型方法) 实例方法(Instance Methods) 实例方法只能用实例 ...

  8. SpringBoot第二十四篇:应用监控之Admin

    作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/11457867.html 版权声明:本文为博主原创文章,转载请附上博文链接! 引言   前一章(S ...

  9. 解剖SQLSERVER 第十四篇 Vardecimals 存储格式揭秘(译)

    解剖SQLSERVER 第十四篇    Vardecimals 存储格式揭秘(译) http://improve.dk/how-are-vardecimals-stored/ 在这篇文章,我将深入研究 ...

随机推荐

  1. Python爬虫视频教程

    ├─第1章_[第0周]网络爬虫之前奏 │ ├─第1节_"网络爬虫"课程内容导学 │ │ 第1部分_全课程内容导学.mp4 │ │ 第2部分_全课程内容导学(WS00单元)学习资料. ...

  2. DotNetCore 3.0 助力 WPF本地化

    概览 随着我们的应用程序越来越受欢迎,我们的下一步将要开发多语言功能.方便越来越多的国家使用我们中国的应用程序, 基于 WPF 本地化,我们很多时候使用的是系统资源文件,可是动态切换本地化,就比较麻烦 ...

  3. Java网络编程与NIO详解4:浅析NIO包中的Buffer、Channel 和 Selector

    微信公众号[黄小斜]作者是蚂蚁金服 JAVA 工程师,目前在蚂蚁财富负责后端开发工作,专注于 JAVA 后端技术栈,同时也懂点投资理财,坚持学习和写作,用大厂程序员的视角解读技术与互联网,我的世界里不 ...

  4. Sqlserver2012 评估期已过问题

    sql server 2012提示评估期已过的解决方法: 第一步:进入SQL2012配置工具中的安装中心. 第二步:再进入左侧维护选项界面,然后选择选择版本升级. 第三步:进入输入产品密钥界面,输入相 ...

  5. Linux Web集群架构详细(亲测可用!!!)

    注意:WEB服务器和数据库需要分离,同时WEB服务器也需要编译安装MySQL. 做集群架构的重要思想就是找到主干,从主干区域向外延展. WEB服务器: apache nginx  本地做三个产品 de ...

  6. 深入浅出TypeScript(1)

    前言 在学习TypeScript过程中,我也是遇到了很多的阻力,因为并未有太多深入挖掘的场景,之前做IONIC的时候,也只是用TS,现如今,这一个系列也是记录自己学习和收获,同时希望自己的这系列教程对 ...

  7. UVA 10395 素数筛

    Twin Primes Twin primes are pairs of primes of the form (p; p + 2). The term \twin prime" was c ...

  8. 完结撒花!129 集 21 个小时,松哥自制的 Spring Boot2 系列视频教程杀青啦!

    松哥的 Spring Boot 教程分为几个阶段. 2016 松哥最早在 2016 年底的时候开始写 Spring Boot 系列的教程,记得当时在广州上班,年底那段时间在深圳出差,在深圳人生地不熟, ...

  9. 怎样才算精通Linux

    1.掌握至少50个以上的常用命令(包括grep.awk.sed.ps.find等等吧,熟练使用,基础的选项不用man) 2.熟悉Gnome/KDE等X-windows桌面环境操作 3.掌握.tgz.. ...

  10. Codeforces 396C

    题意略. 思路: 将树上的节点编好dfs序,然后就可以用树状数组区间修改点查询了. 我们用 lft[v] 和 rht[v]来表示v的子树在dfs序中的左端和右端,这样才方便我们对树状数组的操作. 其实 ...