1. 错误表示
- 在
Swift
中如果我们要定义一个表示错误的类型非常简单, 只要遵循Error
协议就可以了, 我们通常用枚举或结构体来表示错误类型, 枚举可能用的多些, 因为它能更直观的表达当前错误类型的每种错误细节.
enum VendingMachineError: Error {
case invalidSelection
case insufficientFunds(coinsNeeded: Int)
case outOfStock
}
2. 如何抛出错误
- 函数、方法和初始化器都可以抛出错误. 需要在参数列表后面, 返回值前面加
throws
关键字.
func canThrowErrors() throws -> String
func cannotThrowErrors() -> String
e.g.
enum VendingMachineError: Error {
case invalidSelection
case insufficientFunds(coinsNeeded: Int)
case outOfStock
}
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": "Libcorice",
"Eve": "Pretzels"
]
func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
let snackName = favoriteSnacks[person] ?? "Candy Bar"
try vendingMachine.vend(itemNamed: snackName)
}
3. 使用Do-Catch
做错误处理
- 在
Swift
中我们使用do-catch
块对错误进行捕获, 当我们在调用一个throws
声明的函数或方法时, 我们必须把调用语句放在do
语句块中, 同时do
语句块后面紧接着使用catch
语句块.
do {
try <#throwing expression#>
<#statements#>
} catch <#pattern#> {
<#statements#>
} catch <#pattern#> where <#condition#> {
<#statements#>
} catch {
<#statements#>
}
e.g.
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("insufficientFunds funds. Please insert an additional \(coinsNeeded) coins")
} catch {
print("Unexpected error: \(error).")
}
4. try?
-
try?
会将错误转换为可选值, 当调用try?
+ 函数或方法语句时候, 如果函数或方法抛出错误, 程序不会崩溃, 而返回一个nil, 如果没有抛出错误则返回可选值.
e.g.
func someThrowingFunction() throws -> Int {
//...
return 1
}
let x = try? someThrowingFunction()
let y: Int?
do {
y = try someThrowingFunction()
} catch {
y = nil
}
5. try!
- 如果确定一个函数或者方法不会抛出错误, 可以使用
try!
来中断错误的传播.但是如果错误真的发生了, 就会得到一个运行时错误.
e.g.
let phone = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
6. defer
指定退出的清理动作
-
defer
关键字:defer block
里的代码会在函数return
之前执行, 无论函数是从哪个分支return
的, 还是有throw
, 还是自然而然的走到最后一行.
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 scope.
}