以撸代码的形式学习Swift-18:错误处理(Error handling)

错误处理(Error handling)是响应错误以及从错误中恢复的过程。

1 表示并抛出错误

Error空协议表明该类型可以用于错误处理

enum VendingMachineError: Error {
    case InvalidSelection //选择无效 
    case InsufficientFunds(coinsNeeded: Int) //金额不足
    case OutOfStock //缺货
}
throw VendingMachineError.InsufficientFunds(coinsNeeded: 5)

2 处理错误

为了标识出代码中可能会抛出错误的地方,在调用一个能抛出错误的函数、方法或者构造器之前,加上 try 关键字,或者 try? 或 try!这种变体。

四个处理错误的方式:

  1. 用throwing函数传递错误

throwing函数: 在函数声明的参数列表之后加上 throws 关键字,为了表示一个函数、方法或构造器可以抛出错误。

    func canThrowErrors() throws -> String
    func cannotThrowErrors() -> String

一个 throwing 函数可以在其内部抛出错误,并将错误传递到函数被调用时的作用域。
只有 throwing 函数可以传递错误。任何在某个非throwing函数内部抛出的错误只能在函数内部处理。

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 dispenseSnack(snack: String) {
        print("Dispensing \(snack)")
    }
    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
        dispenseSnack(snack: 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)
}
//  throwing构造器能像throwing函数一样传递错误。
struct PurchasedSnack {
    let name: String
    init(name: String, vendingMachine: VendingMachine) throws {
        try vendingMachine.vend(itemNamed: name)
        self.name = name
    }
}
  1. 用 Do-Catch 处理错误
var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8
do {
    try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
} 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.")
}
// 打印 “Insufficient funds. Please insert an additional 2 coins.”
  1. 将错误转换成可选值

如果 someThrowingFunction() 抛出一个错误, x 和 y 的值是 nil,否则 x 和 y 的值就是该函数的返回值。
无论 someThrowingFunction() 的返回值类型是什么类型, x 和 y 都是这个类型的可选类型。
x,y的两种形式类似,try? 更简洁。

func someThrowingFunction() throws -> Int {
    // ...
    return 0
}
let x = try? someThrowingFunction()
let y: Int?
do {
    y = try someThrowingFunction()
} catch {
    y = nil
}
  1. 禁用错误传递

try! 禁止错误传递,如真有错误抛出,就出现运行错误。

let photo = try! loadImage("./Resources/John Appleseed.jpg")

3 指定清理操作

playground文件在andyRon/LearnSwift

推荐阅读更多精彩内容