基本用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| import UIKit
enum PersonErrorType : ErrorType { case OutOfMaxBooks(required: Int) case lessThanZero }
class Person: NSObject { private let maximumBooks = 1000 private var books : Int = 0 override var description : String { return "书柜当前还有\(books)本书" } func purchaseBooks(count: Int) throws { if books + count > maximumBooks { let required = (books + count) - maximumBooks throw PersonErrorType.OutOfMaxBooks(required: required) } books += count } func lendBooks(count: Int) throws { if count > books { throw PersonErrorType.lessThanZero } books -= count } func beginReceipt() { print("又要开始大采买了,真是爽啊") } func endReceipt() { print("购物结束,该去剁手去了") }
class func person() -> Person { let person = Person() try! person.purchaseBooks(100) return person } }
|
这段代码很简单,而且没有用到错误处理,接着我们将这段代码改造一下,让它能使用错误处理
首先,定义一个错误处理类型,在 import 下面添加如下代码:
1 2 3 4
| enum PersonErrorType : ErrorType { case OutOfMaxBooks(required: Int) case OutOfBooks }
|
定义一个枚举,遵守 ErrorType 协议,提供两个错误状态,同时为 OutOfMaxBooks 提供一个关联值,用来指出超出了几本书
接着将买书和借书的方法修改成如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| func purchaseBooks(count: Int) { if books + count > maximumBooks { let required = (books + count) - maximumBooks throw PersonErrorType.OutOfMaxBooks(required: required) } books += count } func lendBooks(count: Int) { if count > books { throw PersonErrorType.lessThanZero } books -= count }
|
在上面的代码中,使用关键字 throws 用来抛出异常,使用 try 来捕获异常。
接下来,进行测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import UIKit
class ViewController: UIViewController {
override func viewDidLoad() { super.viewDidLoad() let person = Person.person() do { try person.purchaseBooks(1500) } catch PersonErrorType.OutOfMaxBooks(let required) { print("书柜满啦,新买的书放不下咯。还差\(required)个空位,赶紧买个新书柜吧") } catch { } do { try person.lendBooks(10000) } catch PersonErrorType.lessThanZero { print("你都没有书啦") } catch { } } }
|
打印结果如下:
swift 配合异常处理的两个新关键字
guard 和 defer
我们为了说明 guard 和 defer 的作用,再定义两个方法 beginReceipt() 和 endReceipt()
1 2 3 4 5 6 7 8 9
| do { person.beginReceipt() try person.purchaseBooks(1500) person.endReceipt() } catch PersonErrorType.OutOfMaxBooks(let required) { print("书柜满啦,新买的书放不下咯。还差\(required)个空位,赶紧买个新书柜吧") } catch { }
|
只有前面一个函数的信息被打印出来了,因为执行 purchaseBooks 方法的时候抛出了错误,程序转移到了 catch 的代码块中,第二个函数没有获得执行的机会了。
这里就可以使用 defer 关键字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| do { person.beginReceipt() defer { person.endReceipt() } try person.purchaseBooks(1500) } catch PersonErrorType.OutOfMaxBooks(let required) { print("书柜满啦,新买的书放不下咯。还差\(required)个空位,赶紧买个新书柜吧") } catch { }
|
这里,就可以使用 defer 来让 endReceipt 在 do 的作用域结束之前得到调用。
guard 就像一个坚盾,判断条件是否满足,不判组就抛出异常。满足后再让代码往下执行,如果此时判断条件中有可选类型,可以使用 guard 将可选类型解绑,具体见 guard
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| func purchaseBooks(count: Int) throws { guard books + count < maximumBooks else { let required = (books + count) - maximumBooks throw PersonErrorType.OutOfMaxBooks(required: required) } books += count } func lendBooks(count: Int) throws { guard count < books else { throw PersonErrorType.lessThanZero } books -= count }
|