1、Swift入门学习笔记(第一版),对Swift的基础知识点进行梳理总结。知识点一直在变,只是作为参考,以苹果官方文档为准~
2、在学习完基本的知识点以后会结合官方文档及相关资料,在此版本的基础上进行添加更改。
十八、错误处理
响应错误以及从错误中恢复的过程,在运行时可恢复错误抛出,捕获,传送和操作的高级支持
1、表示并抛出错误
错误遵循ErrorType
协议的值来表示,可用枚举列出错误情景
enum VendingMachineError: ErrorType {
case InvalidSelection //选择无效
case InsufficientFunds(coinsNeeded: Int) //金额不足
case OutOfStock //缺货
}
使用throw关键字抛出
throw VendingMachineError.OutOfStock
2、处理错误
Swift提供四种方式:
a、把函数抛出的错误传递给调用此函数的代码
b、用do-catch语句处理错误
c、将错误作为可选类型处理
d、断言此错误根本不会发生
2.1、用throwing函数传递错误
func canThrowsErrors() throws -> String
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 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) //调函数说明正在分发物品
}
}
根据上面的描述可看出,vend(itemNamed:)
可能抛出错误
使用try
传递,try
后面跟可能发生错误的区域
定义属性
var vend = VendingMachine()
vend.coinsDeposited = 1
try vend.vend(itemNamed: "Chips")
Output:
错误处理.VendingMachineError.InsufficientFunds(9)
vend.coinsDeposited = 100
try vend.vend(itemNamed: "Chip")
Output:
错误处理.VendingMachineError.InvalidSelection
其他错误就不一一演示了~验证起来十分简单
2.2、用Do-Catch处理错误
var vend = VendingMachine() vend.coinsDeposited = 100
do {
try vend.vend(itemNamed: "Chips")
} 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.")
}
Output:
Dispensing Chips
2.3、将错误转换为可选值
如果抛出错误,那么这个表达式为nil
,否则,即正常情况就是函数的返回值
func someThrowingFunction() throws -> Int {
// ...
}
let x = try? someThrowingFunction()
let y: Int?
do {
y = try someThrowingFunction()
} catch {
y = nil
}
但是不管正不正常,x、y都是可选类型
let result = try?vend.vend(itemNamed: "XXX")
print(result) //结果是nil,因为货物不在清单中
Output:
nil
2.4、使错误传递失效
除try?
外还有try!
处理错误情况,但是try!
是确定没错的情况下值为函数返回值,如果出错直接崩溃。错误不会抛给catch
处理或向上抛出
3、指定清理操作
defer
语句,代码执行要离开当前代码段之前执行的一套语句。不管以何种方式离开(错误或return
或break
等),都会去执行的一些必要的清理工作
defer
关键字与要被延迟执行的语句组成
延迟执行操作是按照被指定的相反顺序执行的,譬如有两个defer
语句,那么第一条defer
在第二条defer
执行之后执行
这里的功能有点类似OC中异常处理机制中的finally
关键字
func testDefer() throws {
print("111111")
defer {
print("Defer1")
}
print("222222")
defer {
print("Defer2")
}
print("333333")
do {
defer {
print("Do-Catch Defer")
}
try vend.vend(itemNamed: "chippppp")
} 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.")
}
}
try testDefer()
Output:
111111
222222
333333
Do-Catch Defer
Invalid Selection.
Defer2
Defer1
注意打印顺序,尤其Do-Catch
中的打印顺序,defer
语句先于catch
打印,可能defer
离开代码段之前的意思可能是外层{ }
,不知道这样理解对不对
如果把do中的代码顺序换下
do {
try vend.vend(itemNamed: "chippppp")
defer {
print("Do-Catch Defer")
}
}
Output:
111111
222222
333333
Invalid Selection.
Defer2
Defer1
会发现do
中defer
语句根本没有执行,没有打印结果,这点在以后的应用中要注意