12. Swift 错误处理的综合例子.png

主动退出程序

  1. Fatal Errors(致命的错误)

    1. fatalError()
    2. fatalError(<message: String>)
  2. Assertions(断言,断言会在 Debug 模式下起作用,但是在 Release 模式中就会被忽略)

    1. assert(<condition: Bool>)
    2. assert(<condition: Bool>, <message: String>)
  3. Preconditions(先决条件,在 Debug 和 Release 模式下都会被执行,除非使用 -Ounchecked 进行编译)

    1. precondition(<condition: Bool>)
    2. precondition(<condition: Bool>, <message: String>)
    3. preconditionFailure()
    4. preconditionFailure(<message: String>)

自定义错误处理

Swift 为运行时可恢复错误的抛出、捕获、传递和操作提供了支持。用于错误处理的类型都得遵守 Error 协议,如枚举、结构体,throw 后边表达式的返回值类型必须遵守 Error 协议。与 Objective-C 的错误处理不同, Swift 不会展开调用栈。

  1. enum EnumError: Error {
  2. case One
  3. case Two
  4. }
  5. struct StructError: Error {
  6. var code: Int
  7. var message: String
  8. var description: String {
  9. return "[StructError] code: \(code), message: \(message)"
  10. }
  11. }
  12. func crash(number: Int) throws -> Int {
  13. if number < 0 {
  14. throw EnumError.One
  15. } else if number == 0 {
  16. throw StructError(code: 10001, message: "number is invalid.")
  17. }
  18. return number
  19. }
  1. do {
  2. let val = try crash(number: 10)
  3. print(val)
  4. }
  5. catch EnumError.One {
  6. print("Throw1: EnumError.One !!")
  7. }
  8. catch let err as StructError {
  9. print("Throw2: \(err)")
  10. print("Throw2: \(err.code)")
  11. }
  12. catch {
  13. /// `error` 是默认提供的错误值
  14. print("Throw3: \(error)")
  15. }
  16. /**
  17. number = -1, Throw1: EnumError.One !!
  18. number = 0, Throw2: StructError(code: 10001, message: "number is invalid.")
  19. Throw2: 10001
  20. number = 10, 10
  21. */
  1. enum HttpError: Error {
  2. case client(statusCode: Int, statusMessage: String)
  3. case server(statusCode: Int, statusMessage: String)
  4. }
  5. func test(code: Int) throws {
  6. if code == 404 {
  7. throw HttpError.client(statusCode: 404, statusMessage: "Not Found")
  8. } else if code == 504 {
  9. throw HttpError.server(statusCode: 504, statusMessage: "Gateway Timeout")
  10. }
  11. }
  12. do {
  13. try test(code: 504)
  14. } catch HttpError.client(let statusCode, let statusMessage) {
  15. print("client error: \(statusCode) - \(statusMessage)")
  16. } catch HttpError.server(let statusCode, let statusMessage) {
  17. print("server error: \(statusCode) - \(statusMessage)")
  18. } catch {
  19. print("other error: \(error)")
  20. }
  1. extension String: Error {
  2. }
  3. func test(code: Int) throws {
  4. if code == 404 {
  5. throw "Not Found"
  6. }
  7. }
  8. do {
  9. try test(code: 404)
  10. } catch {
  11. print("error: \(error)") // error: Not Found
  12. }

调用会抛出异常的函数时,如果调用函数没有对所有错误做处理,则调用函数也需要继续抛出异常,直到有调用函数把错误都处理好了。简单来说,即任何在非抛出函数中抛出错误都必须在函数内部进行处理

  1. enum MyError: Error {
  2. case error1, error2, error3
  3. }
  4. func throw1() throws {
  5. throw MyError.error3
  6. }
  7. func throw2() throws {
  8. do {
  9. try throw1()
  10. } catch MyError.error3 { // 如果这里直接就是`catch`,那么本函数无需`throws`
  11. print("error3")
  12. }
  13. }
  14. func excute() {
  15. do {
  16. try throw2()
  17. } catch {
  18. print(error)
  19. }
  20. }
  21. excute()

guard

  1. guard 关键字必须使用在函数中。
  2. guard 关键字必须和 else 同时出现。
  3. guard 关键字只在条件为 false 的时候才能走 else 语句
  4. guard 的 else 语句必须使用 return 或者 throw、fatalError 结束该作用域,不能继续执行后面的代码
  1. extension String: Error {
  2. }
  3. func buy(productId: String, quantity: Int) throws {
  4. // 条件为假才执行 else 语句,也就是说,guard 省略了 if 为真的情况
  5. guard quantity > 0 else {
  6. throw "quantity must be more than 0"
  7. }
  8. }
  9. do {
  10. try buy(productId: "100323332", quantity: 0)
  11. } catch {
  12. print("error: \(error)")
  13. }
  1. func login(myUsername: String?, myPassword: String?) {
  2. guard let username = myUsername, let password = myPassword else {
  3. print("Error: \(myUsername as Any), \(myPassword as Any)!")
  4. return
  5. }
  6. print("Welcome, \(username), \(password)!")
  7. }
  8. login(myUsername: "huangjian", myPassword: nil)
  9. login(myUsername: "huangjian", myPassword: "Hj123321")

[备注]:guard 和 if 的用法及区别