我尝试理解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