type
status
date
slug
summary
tags
category
icon
password
example-row
example-row
错误处理(Error handling) 是响应错误以及从错误中恢复的过程。Swift 在运行时提供了抛出、捕获、传递和操作可恢复错误(recoverable errors)的一等支持(first-class support)。

表示错误

在 Swift 中,错误用遵循 Error 协议的类型的值来表示,枚举类型尤为适合构建一组相关的错误状态。
抛出错误使用 throw 语句。例如,下面的代码抛出一个错误,提示贩卖机还需要 5 个硬币:

处理错误

某个错误被抛出时,附近的某部分代码必须负责处理这个错误,例如纠正这个问题、尝试另外一种方式、或是向用户报告错误。

用 throwing 函数传递错误

一个标有 throws 关键字的函数被称作throwing函数。如果这个函数指明了返回值类型,throws 关键词需要写在返回箭头(->)的前面。
一个 throwing函数可以在其内部抛出错误,并将错误传递到函数被调用时的作用域。只有 throwing函数可以传递错误。任何在某个非 throwing 函数内部抛出的错误只能在函数内部处理。
上面例子中,VendingMachine 类有一个 vend(itemNamed:) 方法,如果请求的物品不存在、缺货或者投入金额小于物品价格,该方法就会抛出一个相应的 VendingMachineError
 
因为 vend(itemNamed:) 方法会传递出它抛出的任何错误,在代码中调用此方法的地方,必须要么直接处理这些错误——使用 do-catch 语句,try?try!;要么继续将这些错误传递下去。
buyFavoriteSnack(person:vendingMachine:) 同样是一个 throwing 函数,任何由vend(itemNamed:) 方法抛出的错误会一直被传递到buyFavoriteSnack(person:vendingMachine:) 函数被调用的地方。因为 vend(itemNamed:) 方法能抛出错误,所以在调用它的时候在它前面加了 try 关键字。
throwing 构造器能像 throwing 函数一样传递错误。
代码中的 PurchasedSnack 构造器在构造过程中调用了 throwing 函数,并且通过传递到它的调用者来处理这些错误。

用 Do-Catch 处理错误

do 子句中的代码抛出了一个错误,这个错误会与 catch 子句做匹配,从而决定哪条子句能处理它。如果一条 catch 子句没有指定匹配模式,那么这条子句可以匹配任何错误,并且把错误绑定到一个名字为 error 的局部常量。
buyFavoriteSnack(person:vendingMachine:) 函数在一个 try 表达式中被调用,是因为它能抛出错误。如果错误被抛出,相应的执行会马上转移到 catch 子句中,并判断这个错误是否要被继续传递下去。如果错误没有被匹配,它会被最后一个 catch 语句捕获,并赋值给一个 error 常量。如果没有错误被抛出,do 子句中余下的语句就会被执行。 catch 子句不必将 do 子句中的代码所抛出的每一个可能的错误都作处理。如果所有 catch 子句都未处理错误,错误就会传递到周围的作用域。如果错误传递到了顶层作用域却依然没有被处理,将会造成一个运行时错误。
上面代码如果 vend(itemNamed:) 抛出的是一个 VendingMachineError 类型的错误,nourish(with:) 函数会打印一条消息,否则 nourish(with:) 会将错误抛给它的调用方。这个错误之后会被通用的 catch 语句捕获。 捕获多个相关错误的方式是将它们放在 catch 后,通过逗号分隔:

将错误转换成可选值

使用 try? 通过将错误转换成一个可选值来处理错误。
如果 someThrowingFunction() 抛出一个错误,xy 的值是 nil。否则 xy 的值就是该函数的返回值。无论 someThrowingFunction() 的返回值类型是什么类型,xy 都是这个类型的可选类型。因为此函数返回一个整型,所以 xy 是可选整型。

禁用错误传递

有时知道某个 throwing 函数实际运行时是不会抛出错误的,可以在表达式前面写 try! 来禁用错误传递,但是如果真的抛出了错误,将会是一个运行时错误。
上面函数从给定的路径加载图片资源,如果图片无法载入则抛出一个错误。在这种情况下,因为图片是和应用绑定的,正常情况下运行时不会有错误抛出,所以适合禁用错误传递。

指定清理操作

不管是以何种方式离开当前代码块的——无论是由于抛出错误而离开,或是由于诸如 returnbreak 的语句。可以用 defer 语句来确保文件描述符得以关闭,以及手动分配的内存得以释放。
defer 语句将代码的执行延迟到当前的作用域退出之前。该语句由 defer 关键字和要被延迟执行的语句组成。延迟执行的语句不能包含任何控制转移语句,例如 breakreturn 语句,或是抛出一个错误。延迟执行的操作会按照它们声明的顺序从后往前执行——也就是说,第一条 defer 语句中的代码最后才执行,第二条 defer 语句中的代码倒数第二个执行,以此类推。最后一条语句会第一个执行。
 
【swift002】可选类型【swift004】断言和先决条件
  • Twikoo