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()
抛出一个错误,x
和 y
的值是 nil
。否则 x
和 y
的值就是该函数的返回值。无论 someThrowingFunction()
的返回值类型是什么类型,x
和 y
都是这个类型的可选类型。因为此函数返回一个整型,所以 x
和 y
是可选整型。禁用错误传递
有时知道某个
throwing
函数实际运行时是不会抛出错误的,可以在表达式前面写 try!
来禁用错误传递,但是如果真的抛出了错误,将会是一个运行时错误。上面函数从给定的路径加载图片资源,如果图片无法载入则抛出一个错误。在这种情况下,因为图片是和应用绑定的,正常情况下运行时不会有错误抛出,所以适合禁用错误传递。
指定清理操作
不管是以何种方式离开当前代码块的——无论是由于抛出错误而离开,或是由于诸如
return
、break
的语句。可以用 defer
语句来确保文件描述符得以关闭,以及手动分配的内存得以释放。defer
语句将代码的执行延迟到当前的作用域退出之前。该语句由 defer
关键字和要被延迟执行的语句组成。延迟执行的语句不能包含任何控制转移语句,例如 break
、return
语句,或是抛出一个错误。延迟执行的操作会按照它们声明的顺序从后往前执行——也就是说,第一条 defer
语句中的代码最后才执行,第二条 defer
语句中的代码倒数第二个执行,以此类推。最后一条语句会第一个执行。- 作者:黄x黄
- 链接:https://hxhowl.site/article/swift003
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章