我尝试理解 swift 2 中的新错误处理。这是我所做的:我首先声明了一个错误枚举:
enum SandwichError: ErrorType { case NotMe case DoItYourself }
然后我声明了一个引发错误的方法(不是异常,这是一个错误。)。这是那个方法:
func makeMeSandwich(names: [String: String]) throws -> String { guard let sandwich = names["sandwich"] else { throw SandwichError.NotMe } return sandwich }
问题出在调用方。下面是调用这个方法的代码:
let kitchen = ["sandwich": "ready", "breakfeast": "not ready"] do { let sandwich = try makeMeSandwich(kitchen) print("i eat it \(sandwich)") } catch SandwichError.NotMe { print("Not me error") } catch SandwichError.DoItYourself { print("do it error") }
do在行编译器Errors thrown from here are not handled because the enclosing catch is not exhaustive说. 但在我看来,它是详尽无遗的,因为SandwichError枚举中只有两种情况。
do
Errors thrown from here are not handled because the enclosing catch is not exhaustive
SandwichError
对于常规的 switch 语句,swift 可以理解在处理每个案例时它是详尽的。
Swift 2 错误处理模型有两点很重要:穷举性和弹性。总之,它们归结为您的do/catch语句需要捕获所有可能的错误,而不仅仅是您知道可以抛出的错误。
catch
请注意,您没有声明一个函数可以抛出什么类型的错误,只声明它是否抛出。这是一个零一无穷大的问题:作为一个定义一个函数供他人(包括你未来的自己)使用的人,你不希望你的函数的每个客户端都适应你的实现中的每一个变化函数,包括它可能抛出的错误。您希望调用您的函数的代码能够适应这种变化。
因为你的函数不能说它会抛出什么样的错误(或者将来可能会抛出),所以catch捕获它的块不知道它可能会抛出什么样的错误。因此,除了处理您知道的错误类型之外,您还需要使用通用catch语句来处理您不知道的错误类型——这样,如果您的函数更改了它在未来抛出的错误集,调用者仍然会捕获它错误。
do { let sandwich = try makeMeSandwich(kitchen) print("i eat it \(sandwich)") } catch SandwichError.NotMe { print("Not me error") } catch SandwichError.DoItYourself { print("do it error") } catch let error { print(error.localizedDescription) }
但我们不要止步于此。再想一想这种弹性的想法。你设计三明治的方式,你必须在你使用它们的每个地方描述错误。这意味着每当您更改错误案例集时,您都必须更改使用它们的每个地方……这不是很有趣。
定义你自己的错误类型背后的想法是让你集中这样的事情。你可以为你的错误定义一个description方法:
description
extension SandwichError: CustomStringConvertible { var description: String { switch self { case NotMe: return "Not me error" case DoItYourself: return "Try sudo" } } }
然后你的错误处理代码可以要求你的错误类型来描述自己——现在你处理错误的每个地方都可以使用相同的代码,也可以处理未来可能出现的错误情况。
do { let sandwich = try makeMeSandwich(kitchen) print("i eat it \(sandwich)") } catch let error as SandwichError { print(error.description) } catch { print("i dunno") }
这也为错误类型(或它们的扩展)铺平了道路,以支持其他报告错误的方式——例如,你可以在你的错误类型上有一个扩展,它知道如何向UIAlertControlleriOS 用户报告错误。
UIAlertController