你可以使用错误处理(error handling)来应对程序执行中可能遇到的错误条件。
相对于可选中运用值的存在与缺失来表达函数的成功与失败,错误处理可以推断失败的原因,并传播至程序的其他部分。
当一个函数遇到错误条件,它能报错。调用函数的地方能抛出错误消息并合理处理。
func canThrowAnError() throws {
// 这个函数可能抛出错误
}
一个函数可以通过在声明添加 throws
关键字来抛出错误消息。当你的函数能抛出错误消息时,你应该在表达式中前置 try
关键词。
do {
try canThrowAnError()
// 没有错误消息抛出,继续执行后续代码
} catch {
// 有错误消息抛出,执行后续代码
}
一个 do
语句创建了一个新的包含作用域,使得错误能被传播到一个或多个 catch
从句。
这里有一个错误处理如何用来应对不同错误条件的例子。
func makeASandwich() throws {
// ...
}
do {
try makeASandwich()
eatASandwich()
} caych SandwichError.outOfCleanDishes {
wachDishes()
} cathc SandwichError.missingIngeredients(let ingredients) {
buyGroceries(ingredients)
}
在此例中,makeASandwich()
(做一个三明治)函数会抛出一个错误消息如果没有干净的盘子或者某个原料缺失。因为 makeASandwich()
抛出错误,函数调用被包裹在 try
表达式中。将函数包裹在一个 do
语句中,任何被抛出的错误会被传播到提供的 catch
从句中。
如果没有错误被抛出,eatASandwich()
函数会被调用。如果一个匹配 SandwichError.outOfCleanDishes
的错误被抛出,washDishes()
函数会被调用。如果一个匹配 SandwichError.missingIngredients
的错误被抛出,buyGroceries(_:)
函数会被调用,并且使用 catch
所捕捉到的关联值 [String]
作为参数。
断言和先决条件
断言和先决条件是在运行时所做的检查。你可以用它们来检查在执行后续代码之前是否一个必要的条件已经被满足了。如果断言或者先决条件中的布尔条件评估的结果为 true
,则代码像往常一样执行。如果布尔条件评估结果为 false
,程序的当前状态是无效的,则代码执行结束,应用程序中止。
你使用断言和先决条件来表达你所做的假设和你在编码时候的期望。你可以将这些包含在你的代码中。断言帮助你在开发阶段找到错误和不正确的假设,先决条件帮助你在生产环境中探测到存在的问题。
除了在运行时验证你的期望值,断言和先决条件也变成了一个在你的代码中的有用的文档形式。和在上面讨论的错误处理不同,断言和先决条件并不是用来处理可恢复的或者可预期的错误。因为一个断言失败表明了程序正处于一个无效的状态,没有办法去捕获一个失败的断言。
使用断言和先决条件不是一个能够避免程序出现无效状态的编码方法。然而,如果一个无效状态产生了,断言和先决条件可以强制检查你的数据和程序状态,使你的程序可预测的中止(不是系统强制的,被动的中止),并帮助使这个问题更容易调试。一旦探测到无效的状态,执行则被中止,防止无效的状态导致的进一步对系统的伤害。
断言和先决条件的不同点是,它们什么时候进行状态检测:断言仅在调试环境运行,而先决条件则在调试环境和生产环境中运行。在生产环境中,断言的条件将不会进行评估。这个意味着你可以使用很多断言在你的开发阶段,但是这些断言在生产环境中不会产生任何影响。
使用断言进行调试
你可以调用Swift标准库的 assert(_:_:file:line:)
函数来写一个断言。向这个函数传入一个结果为 true
或者 false
的表达式以及一条信息,当表达式的结果为 false
的时候这条信息会被显示:
let age = -3
assert(age >= 0, "A person's age cannot be less than zero")
// 因为 age < 0,所有断言会触发
在这个例子中,只有 age >= 0
为 true
时,即 age
的值非负的时候,代码才会继续执行。如果 age
的值是负数,就像代码中的那样,age >= 0
为 false
,断言被触发,终止应用。
如果不需要断言信息,可以像这样忽略掉:
assert(age >= 0)
如果代码已经检查了条件,你可以使用 assertionFailure(_:file:line)
函数来表明断言失败了,例如:
if age > 10 {
print("You can ride the roller-coaster or the ferris wheel.")
} else if age > 0 {
print("You can ride the ferris wheel.")
} else {
assertionFailure("A person's age can't be less than zero.")
}
强制执行先决条件
当一个条件可能为 false
,但是继续执行代码要求条件必须为 true
的时候,需要使用先决条件。例如使用先决条件来检查是否下标越界,或者来检查是否将一个正确的参数传给函数。
你可以使用全局 precondition(_:_:file:line:)
函数来写一个先决条件。向这个函数传入一个结果为 true
或者 false
的表达式以及一条信息,当表达式结果为 false
的时候这条信息会被显示:
// 在一个下标的实现里...
precondition(index > 0, "Index must be greater than zero.")
你可以调用 precondition(_:_:file:line)
方法来表明出现了一个错误。
注意: 如果你使用unchecked模式(-Ounchecked)编译代码,先决条件将不会进行检查。编译器假设所有的先决条件总是为true(真),他将优化你的代码。然而,
fatalError(_:file:line:)
函数总是中断执行,无论你怎么进行优化设定。 你能使用fatalError(_:file:line:)
函数在设计原型和早期开发阶段,这个阶段只有方法的声明,但是没有具体实现,你可以在方法体中写上fatalError("Unimplemented")作为具体实现。因为fatalError不会像断言和先决条件那样被优化掉,所以你可以确保当代码执行到一个没有被实现的方法时,程序会被中断。