Swift中的错误处理:try/catch 与更多(高级水平)
\n\n错误处理是 Swift 开发中的关键主题之一。如果您已经熟悉基本的 do-catch 和 try?,那么是时候进入下一个层次了。在本文中,我们将深入探讨高级技巧:使用 Error 协议、Result 类型、rethrows 关键字,以及如何在真实的 iOS/macOS 项目中正确设计错误层次结构。
深入理解 Error 协议与自定义错误
\n\n在 Swift 中,任何错误都必须符合 Error 协议。然而,为了使代码更具可读性和可维护性,建议创建带有嵌套 case 和关联值的自定义枚举(enum)。
enum NetworkError: Error {\n case invalidURL\n case noData\n case decodingFailed(description: String)\n case serverError(statusCode: Int)\n case timeout(seconds: Double)\n}\n\n// 使用示例\nfunc fetchUser(id: Int) throws -> User {\n guard id > 0 else {\n throw NetworkError.invalidURL\n }\n // ... 请求逻辑\n if someCondition {\n throw NetworkError.serverError(statusCode: 500)\n }\n return User()\n}\n\n这种方法允许传递额外的上下文信息:错误代码、描述或超时时间。这在日志记录和调试时特别有用。
\n\nResult:异步代码中 do-catch 的替代方案
\n\nResult<Success, Failure> 类型是一个强大的工具,源自函数式编程。它非常适合基于回调的 API、网络请求和异步操作。
enum DataError: Error {\n case corrupted\n case notFound\n}\n\nfunc loadImage(from url: URL, completion: @escaping (Result<UIImage, DataError>) -> Void) {\n DispatchQueue.global().async {\n // 模拟加载\n if arc4random_uniform(2) == 0 {\n completion(.success(UIImage()))\n } else {\n completion(.failure(.notFound))\n }\n }\n}\n\n// 使用\nloadImage(from: someURL) { result in\n switch result {\n case .success(let image):\n print("图片已加载: \\(image)")\n case .failure(let error):\n print("错误: \\(error.localizedDescription)")\n }\n}\n\nResult 使代码更可预测,并消除了处理 nil 可选值的需要。此外,您可以使用 .map 和 .flatMap 进行转换链。
Rethrows:当函数“传递”错误时
\n\nrethrows 关键字是 Swift 中最被低估的功能之一。它允许编写一个本身不抛出错误,但会“传递”传入闭包(closure)抛出的错误的函数。
func performOperation<T>(on array: [T], operation: (T) throws -> Bool) rethrows -> [T] {\n var result: [T] = []\n for element in array {\n if try operation(element) {\n result.append(element)\n }\n }\n return result\n}\n\n// 无错误(不需要 try)\nlet numbers = [1, 2, 3, 4, 5]\nlet evenNumbers = performOperation(on: numbers) { $0.isMultiple(of: 2) }\nprint(evenNumbers) // [2, 4]\n\n// 有错误(需要 try)\nenum ValidationError: Error { case negative }\nlet filtered = try performOperation(on: numbers) { value in\n guard value > 0 else { throw ValidationError.negative }\n return value % 2 == 0\n}\n\nrethrows 使 API 更加灵活:用户可以传递普通闭包(无需 try),也可以传递带有 throws 的闭包(此时需要 try)。这在 Swift 标准库中经常使用——例如,在 map、filter 和 for 中。