Skip to content

Swift 入门(14):错误处理

在 Swift 中,错误处理主要通过 throw / try / catch 来实现。
和异常不同,Swift 错误必须显式声明和处理,更安全。

1. 定义错误类型

Swift 的错误必须遵循 Error 协议。

swift
enum FileError: Error {
    case notFound
    case noPermission
}

2. 抛出错误

swift
func readFile(name: String) throws -> String {
    if name == "secret.txt" {
        throw FileError.noPermission
    }
    return "文件内容"
}

3. 捕获错误

swift
do {
    let content = try readFile(name: "secret.txt")
    print(content)
} catch FileError.notFound {
    print("❌ 文件未找到")
} catch FileError.noPermission {
    print("⛔ 没有权限")
} catch {
    print("⚠️ 其它错误:\(error)")
}

4. try? 和 try!

  • try?:错误时返回 nil
  • try!:确定不会出错时使用,出错会崩溃。
swift
let result1 = try? readFile(name: "a.txt")  // Optional("文件内容")
let result2 = try? readFile(name: "secret.txt")  // nil

let result3 = try! readFile(name: "a.txt") // 强制执行

5. defer(清理资源)

defer 块中的代码在函数结束时执行,常用于释放资源。

swift
func processFile() throws {
    print("开始处理文件")
    defer {
        print("关闭文件")
    }
    throw FileError.notFound
}

try? processFile()
// 输出:
// 开始处理文件
// 关闭文件

defer 的实战应用:回调清理

swift
// 系统 API 回调中的资源清理
public func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
    defer {
        self.callback = nil  // 确保函数退出前清理回调
    }
    self.callback?(self.toJSON(["ok": false, "errMsg": error.localizedDescription]))
}

defer 的执行时机

swift
func demonstrateDefer() {
    print("1. 函数开始")

    defer {
        print("4. defer 块执行")
    }

    print("2. 中间逻辑")

    if someCondition {
        print("3a. 提前返回")
        return  // defer 仍会执行
    }

    print("3b. 正常结束")
    // defer 在这里执行
}

// 输出(提前返回情况):
// 1. 函数开始
// 2. 中间逻辑
// 3a. 提前返回
// 4. defer 块执行

多个 defer 的执行顺序

swift
func multipleDefer() {
    defer { print("第一个 defer") }
    defer { print("第二个 defer") }
    defer { print("第三个 defer") }

    print("函数主体")
}

multipleDefer()
// 输出(后进先出 LIFO):
// 函数主体
// 第三个 defer
// 第二个 defer
// 第一个 defer

defer 的实际应用场景

swift
// 1. 文件操作清理
func readFileWithCleanup(_ path: String) -> String? {
    let file = openFile(path)
    defer {
        closeFile(file)  // 确保文件被关闭
    }

    guard file.isValid else { return nil }
    return file.readContent()
}

// 2. 网络请求状态管理
func performNetworkRequest() {
    isLoading = true
    defer {
        isLoading = false  // 确保加载状态被重置
    }

    // 网络请求逻辑
    if requestFailed {
        return  // defer 仍会执行,isLoading 会被设为 false
    }

    processResponse()
}

// 3. 数据库事务管理
func updateDatabase() throws {
    let transaction = database.beginTransaction()
    defer {
        if transaction.isActive {
            transaction.rollback()  // 确保事务被回滚或提交
        }
    }

    try database.insert(record1)
    try database.insert(record2)

    transaction.commit()
}

// 4. 认证回调清理(你的代码)
class AuthManager {
    private var callback: ((String) -> Void)?

    func authenticate(_ options: String, _ cb: @escaping (String) -> Void) {
        self.callback = cb
        // 执行认证...
    }

    // 成功回调
    func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        defer {
            self.callback = nil  // 确保回调被清理
        }

        // 处理成功结果
        let result = processAuthorization(authorization)
        self.callback?(result)
    }

    // 失败回调(你的代码)
    public func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
        defer {
            self.callback = nil  // 无论如何都清理回调
        }
        self.callback?(self.toJSON(["ok": false, "errMsg": error.localizedDescription]))
    }
}

defer vs 普通清理的对比

swift
// ❌ 容易遗漏清理的写法
func badCleanupExample() {
    self.callback = someCallback

    if condition1 {
        self.callback = nil  // 需要手动清理
        return
    }

    if condition2 {
        // 忘记清理 callback!
        return
    }

    doSomething()
    self.callback = nil  // 需要手动清理
}

// ✅ 使用 defer 确保清理
func goodCleanupExample() {
    defer {
        self.callback = nil  // 自动清理,不会遗漏
    }

    self.callback = someCallback

    if condition1 {
        return  // defer 自动执行
    }

    if condition2 {
        return  // defer 自动执行
    }

    doSomething()
    // defer 自动执行
}

总结

  • enum + Error 定义错误类型。
  • throw 抛出,用 try + catch 捕获。
  • try? 返回可选,try! 强制执行。
  • defer 用于清理收尾。

本站总访问