本文主要是介绍swift2.1_Language Guide_Error Handling,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
这部分是新增的,加在第18节
18Error Handling
异常处理是在你程序中响应和捕获异常的处理过程
一些处理并不保证总是成功执行或产生有用的输出。可选值可用来代表一个值是否存在,但当操作失败时,搞清楚什么原因导致失败并做相应处理往往很重要。
考虑一个例子,读取和处理磁盘上一个文件的数据。有多种原因可能导致失败,包括文件不存在,没有读取权限,或编码格式不匹配等。区分这些不同的情况需要程序捕获异常然后再提示用户。
NOTE
异常处理的处理方式不同于Cocoa和OC中得NSError的方式。参见Using Swift with Cocoa and Objective-C 中 Error Handling
18.1Representing and Throwing Errors
表示和抛出异常
在swift中,异常用符合ErrorType协议的类型值表示。这个协议代表一个可以用作异常处理的类型
枚举类型可以很好的代表一组相关的异常情况,还可以有参数来增加额外的信息。比如:自动售卖机的错误信息可以类似如下:
enum VendingMachineError: ErrorType {
case InvalidSelection
case InsufficientFunds(coinsNeeded: Int)
case OutOfStock
}
抛出异常说明有不正常的情况发生,正常流程无法继续进行。
用throw语句来抛出异常。比如,下面的代码抛出一个异常指明售货机还要你5个硬币
throw VendingMachineError.InsufficientFunds(coinsNeeded: 5)
18.2Handling Errors
有4种方法处理异常
1,抛出给外层处理
2,使用do-catch语句处理
3,用可选值处理
4,断言不会发生异常
这些后面会详细介绍
当一个函数抛出异常,他将改变程序的流程,所以在你的代码中定位可能出现异常的位置就很重要。为了定位异常位置,在调用函数,方法或初始化前使用try,try?,try!关键字。这些关键字后面会再进行描述。
NOTE
swift的异常处理类似一些其他的语言,使用try,catch和throw关键字。而不像另一些语言(包括Objective-C)。error handling in Swift does not involve unwinding the call stack, a process that can be computationally expensive. As such, the performance characteristics of a throw statement are comparable to those of a return statement.
18.2.1Propagating Errors Using Throwing Functions
为了说明一个函数,方法或构造函数可能抛出异常,在声明中的参数后面写上shrows关键字。标记有throws的函数称为throwing function。如果函数有返回值,那么throws写在返回值的箭头前面。
func canThrowErrors() throws -> String
func cannotThrowErrors() -> String
NOTE
只有throwing function可以抛出异常,nonthrowing function中的异常,必须在自己内部处理掉
下面的例子中VendingMachine得vend(itemNamed:)方法会抛出异常
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(itemName:)方法使用了guard语句,如果要求不能满足,则将提前退出并抛出异常。只有所有条件都满足时才能售货成功。
因为vend(itemNamed:)可能抛出异常,所以调用时必须处理,可以使用do-catch语句,try?或 try!, 或是继续往外抛出。
下面是继续往外抛的例子:
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)
}
因为vend(itemNamed:)方法会抛出异常,前面要加try
18.2.2Handling Errors Using Do-Catch
如果do中抛出异常,则将通过匹配catch来决定那段代码来处理异常
do {
try expression
statements
} catch pattern 1 {
statements
} catch pattern 2 where condition {
statements
}
pattern用来指明他可以处理哪些异常,如果一个catch没有pattern,那么他将可以处理所有的异常
catch分句不需要处理所有可能的异常。如果没有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.")
}
// prints "Insufficient funds. Please insert an additional 2 coins."
18.2.3Converting Errors to Optional Values
可以使用try?把异常包装成一个可选值。如果有异常抛出,则可选值将为nil。下面的代码中,x和y的值将会是相等的
func someThrowingFunction() throws -> Int {
// ...
}
let x = try? someThrowingFunction()
let y: Int?
do {
y = try someThrowingFunction()
} catch {
y = nil
}
如果有异常,则x和y的值为nil,如没有异常,则是函数的返回值。
使用try?可以使你能够更便捷的处理异常。
下面的例子用两种方式获取数据,如果都失败则返回nil
func fetchData() -> Data? {
if let data = try? fetchDataFromDisk() { return data }
if let data = try? fetchDataFromServer() { return data }
return nil
}
18.2.4Disabling Error Propagation
有时你知道这些函数,方法在运行时并不会抛出异常。这时你可以使用try!来断言不会发生异常。假如实际上却发生异常了,将抛出运行时异常。
下例,函数导入图片资源,因为图片资源随应用打包,所以不会发生异常,这是你就可以try!
let photo = try! loadImage("./Resources/John Appleseed.jpg")
18.3Specifying Cleanup Actions
如果你想在执行流离开当前代码块前执行一部分代码,你可以使用defer语句块。
不管执行流以何种方式离开当前代码块,不管是异常,还是rutuen,或是break,defer语句块都能让你做必要的清理。
因此,你可以使用defer语句块来确保你在打开文件后有关掉它,你开辟的空间有释放他。
defer语句推迟语句内容到当前块结束时执行。defer内容不能有跳出语句,如break和return,也不能抛出异常。当有多个defer语句块时,将倒序执行。
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 the scope.
}
}
上面defer语句块,确保文件会被关闭
func test(){
defer{
print("11111")
}
defer{
print("22222")
}
defer{
print("33333")
}
}
test()
//print 33333
//print 22222
//print 11111
这篇关于swift2.1_Language Guide_Error Handling的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!