WWDC 2015 宣布了新的 Swift 2.0. 这次重大更新给 Swift 提供了新的异常处理方法。这篇文章会主要围绕这个方面进行讨论。
如何建造异常类型?
在 iOS 开发当中,我们会面对很多异常处理。在 Cocoa Touch 中我们使用 NSError
来进行异常处理。在新的 Swift 2.0 中,我们可以使用新的 ErrorType
protocol。
在 Swift 中, enum
是最好的方法建立属于你自己的异常类型,你只要在你的 enum
中确认新的 ErrorType
。
enum MyError: ErrorType {
case NotExist
case OutOfRange
}
如何抛出异常
在抛出异常之前,我们需要在函数或方法的返回箭头 ->
前使用 throws
来标明将会抛出异常
func myMethodRetrunString() throws -> String
// No return, we can just add throws in the end
func myMethodRetrunNothing() throws
声明之后, 我们需要在函数或者方法里扔出异常,很简单使用throw
就可以了
func myMethod() throws
//...
// item is an optional value
guard let item = item else {
// need throws the error out
throw MyError.NotExist
}
// do with item
}
上面这段代码使用了 guard
来进行unwrap optional value。这是 Swift 2.0 提供的一个新的方法。
Guard
在 Haskell, Erlang 等语言中早已存在 guard
, 在这里有更多关于它的介绍。
guard
翻译过来可以理解为守护,守卫。
在 Swift 中,guard
有点像 if
但是他们有两个非常重要的区别
-
guard
必须强制有else
语句 - 只有在
guard
审查的条件成立,guard
之后的代码才会运行 (像守卫一样,条件不符就不让过去)。
guard
中的 else
只能执行转换语句,像 return
, break
, continue
或者 throws
当然你也可以在这里返后一个函数或者方法。
值得注意的是,guard
的使用会提高你代码的可读性,但是也代表你的代码的执行会有非常明确的顺序性,这一点需要开发者们留心处理。
虽然我们在异常处理中提到了 guard
但是不代表它只能在异常处理中使用。它具有广泛的适用性,或许过阵子我会专门为 guard
的使用写篇文章。
如何获取并处理异常?
上文讲述了如何建造抛出异常,获取和处理异常就变得很简单了。使用 do-catch
机制。
do {
try functionWillThrowError()
} catch {
// deal with error
}
do-catch
机制简单易懂。很多编程语言也使用类似的机制进行异常处理,但是在 Swift 中有一个比较重要的特性。
catch
和 switch
一样具有 Pattern Matching 的能力。所以,使用 catch
你可以对异常的解析进行更为高级的处理
do {
try functionWillThrowError()
} catch MyError.NotExist {
// deal with not exist
} catch MyError.OutOfRange {
// deal with not exist
}
这里值得提一下在 Swift 2.0中一个跟异常处理没有关系的改进
Swift 2.0 中没有了
do-while
循环,取而代之的是repeat-while
。苹果说这个改动是为了增强代码的可读性。但是我更觉得是为了让我们更舒服的使用do-catch
不处理异常
如果我不想处理异常怎么办,或者说,我非常确定某个方法或者函数虽然声明会抛出异常,但是我自己知道我在使用时候是绝对不会抛出任何异常的。这种情况下 我们可以使用 try!
try! functionThrowErrorNil()
当然,如果你使用 try!
,而你的方法或者函数抛出了异常,那么你会得到一个运行中异常 (runtime error) 所以我们开发者需要慎用哦。
Defer
文章结束前我们再讨论下 defer
在你的代码块就要结束前。如果你使用了 defer
。 在其之中的代码就会运行。等于说,给了你最后的机会来进行一些处理。如果你熟悉 BDD 或者 TDD, 那么你可以参考他们中的 aferAll
机制
func myFunction() throws {
defer {
// No matter what happened I need do something
print("All done, clean up here")
}
guard let item = item else {
// need throws the error out
throw MyError.NotExist
}
guard item.count > maxNumber else {
// need throws the error out
throw MyError.OutOfRange
}
// do something with item
// ...
}
注意,如果你有多个
defer
语句,他们在执行的顺序会和栈一样,最后一个进,第一个出。
总结
- 使用
ErrorType
的帮助建立你的异常类型 - 使用
throws
来声明异常,用throw
来抛出异常 - 使用
do-catch
机制来获取和处理异常