Swift Examples - Error Handling

The Swift Programming Language Examples

源码在 GitHub:https://github.com/gewill/The-Swift-Programming-Language-2.1-Examples

Playground ->

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// : Playground - noun: a place where people can play

import UIKit

//: 错误处理(Error Handling)

//说实话错误处理这里,习惯了 AFNetworking 方式的闭包或者 block。因为闭包可以返回更过参数如:错误类型/错误内容/其他参数
//这里学会三种调用方法即可,try? 最方便,如不打算考虑处理错误信息


enum VendingMachineError: ErrorType {
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 dispenseSnack(snack: String) {
print("Dispensing \(snack)")
}

func vend(itemNamed name: String) throws {
guard var 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
--item.count
inventory[name] = item
dispenseSnack(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)
}

//: 用 Do-Catch 处理错误
var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8
do {
try buyFavoriteSnack("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.”


//: 将错误转换成可选值

func fetchData() -> Data? {
if let data = try? fetchDataFromDisk() { return data }
if let data = try? fetchDataFromServer() { return data }
return nil
}

//: 禁用错误传递

//有时你知道某个 throwing 函数实际上在运行时是不会抛出错误的,在这种情况下,你可以在表达式前面写try!来禁用错误传递,这会把调用包装在一个断言不会有错误抛出的运行时断言中。如果实际上抛出了错误,你会得到一个运行时错误。

//例如,下面的代码使用了loadImage(_:)函数,该函数从给定的路径加载图片资源,如果图片无法载入则抛出一个错误。在这种情况下,因为图片是和应用绑定的,运行时不会有错误抛出,所以适合禁用错误传递:

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

//: 指定清理操作
//可以使用defer语句在即将离开当前代码块时执行一系列语句。

func processFile(filename: String) throws {
if exists(filename) {
let file = open(filename)
defer {
close(file)
}
while let line = try file.readline() {
// 处理文件。
}
// close(file) 会在这里被调用,即作用域的最后。
}
}