错误处理是响应错误以及从错误中返回的过程。swift提供第一类错误支持,包括在运行时抛出,捕获,传送和控制可回收错误。
一些函数和方法不能总保证能够执行所有代码或产生有用的输出。可空类型用来表示值可能为空,但是当函数执行失败的时候,
可空通常可以用来确定执行失败的原因,因此代码可以正确地响应失败。在Swift中,这叫做抛出函数或者抛出方法。
在Swift中,错误用符合ErrorType协议的值表示。 Swift枚举特别适合把一系列相关的错误组合在一起,
同时可以把一些相关的值和错误关联在一起。因此编译器会为实现ErrorType协议的Swift枚举类型自动实现相应合成。
//贩卖机错误
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 {
throwVendingMachineError.InvalidSelection
}
guard item.count >0 else {
throwVendingMachineError.OutOfStock
}
guard item.price <=coinsDeposited else {
throwVendingMachineError.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 {
try expression
statements
} catch pattern1 {
statements
} catch pattern2 where condition {
statements
}
*/
var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited =11
do {
try buyFavoriteSnack("Alice", vendingMachine:vendingMachine)
print("No Errors throw")
} 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.")
}
//No Errors throw,如果vendingMachine.coinsDeposited这会打印出
//Insufficient funds. Please insert an additional 2 coins.print("No Errors throw")不会执行
/*转换错误为可选值
用try?来讲错误处理转化成一个可选值,如果一个错误抛出,那么用了try?的表达值的值为nil
*/
func someThrowingFunction() throws -> Int {
return 0
}
let x = try?someThrowingFunction()
let y:Int?
do {
y =try someThrowingFunction()
}catch{
y = nil
}
//如果错误抛出, x,y的值都为nil,注x,y:都为可选类型
/*利用try?来以相同方式处理所有错误
func fetchData() -> Data? {
if let data = try? fetchDataFromDisk() {return data}
if let data = try? fetchDataFromServer() {return data}
return nil
}
*/
/* 禁止错误传播
通过try!来调用抛出函数或方法禁止了错误传送,并且把调用包装在运行时断言,这样就不会抛出错误。
如果错误真的抛出了,会触发运行时错误。
let photo = try! loadImag("./Resources/John Appleseed.jpg")
*/
指定清理操作
使用defer(推迟)语句来在执行一系列的语句。这样不管有没有错误发生,都可以执行一些必要的收尾操作。
包括关闭打开的文件描述符以及释放所有手动分配的内存。
defer语句把执行推迟到退出当前域的时候。defer语句包括defer关键字以及后面要执行的语句。
被推迟的语句可能不包含任何将执行流程转移到外部的代码,比如break或者return语句,或者通过抛出一个错误。
被推迟的操作的执行的顺序和他们定义的顺序相反,也就是说,在第一个defer语句中的代码在第二个defer语句中的代码之后执行。
func processFile(filename: String) throws {
if exists(filename) {
let file = open(filename)
defer {
close(file)
}
while let line = try file.readLine() {
//work width the file.
}
//close(file) is called here, at eht end of the scope.
}
}
*/