Swift 中的错误处理机制是什么?如何使用 throws、throw、try、catch 处理错误?
Swift 提供了一套完整的错误处理机制,允许开发者优雅地处理运行时错误。Swift 的错误处理模型与异常处理类似,但更加类型安全和可控。
错误定义:
- 使用
Error协议定义错误类型 - 可以使用枚举定义具体的错误情况
- 可以关联错误信息
- 示例:
swift
enum NetworkError: Error { case invalidURL case requestFailed(Int) case noData case decodingError } enum FileError: Error { case notFound case permissionDenied case corrupted }
抛出错误:
- 使用
throws关键字标记可能抛出错误的函数 - 使用
throw关键字抛出错误 - 示例:
swift
func fetchData(from urlString: String) throws -> Data { guard let url = URL(string: urlString) else { throw NetworkError.invalidURL } let (data, response) = try URLSession.shared.data(from: url) guard let httpResponse = response as? HTTPURLResponse else { throw NetworkError.requestFailed(0) } guard httpResponse.statusCode == 200 else { throw NetworkError.requestFailed(httpResponse.statusCode) } return data }
处理错误:
-
使用 try-catch:
swiftdo { let data = try fetchData(from: "https://api.example.com/data") print("Data received: \(data)") } catch NetworkError.invalidURL { print("Invalid URL") } catch NetworkError.requestFailed(let statusCode) { print("Request failed with status: \(statusCode)") } catch { print("Unexpected error: \(error)") } -
使用 try?:
- 将错误转换为可选值
- 如果发生错误,返回 nil
- 示例:
swift
let data = try? fetchData(from: "https://api.example.com/data") if let data = data { print("Data received: \(data)") } else { print("Failed to fetch data") }
-
使用 try!:
- 强制解包,确定不会抛出错误时使用
- 如果抛出错误,会触发运行时错误
- 示例:
swift
let data = try! fetchData(from: "https://api.example.com/data") print("Data received: \(data)")
defer 语句:
- 在代码块退出前执行清理操作
- 无论是否发生错误都会执行
- 示例:
swift
func processFile(at path: String) throws { let fileHandle = try FileHandle(forReadingFrom: URL(fileURLWithPath: path)) defer { fileHandle.closeFile() } let data = fileHandle.readDataToEndOfFile() return data }
rethrow:
- 将捕获的错误重新抛出
- 用于包装函数
- 示例:
swift
func processData(_ urlString: String) throws -> Data { let data = try fetchData(from: urlString) return data }
Result 类型:
- 使用
Result<Success, Failure>类型处理错误 - 更函数式的错误处理方式
- 示例:
swift
func fetchDataResult(from urlString: String) -> Result<Data, Error> { guard let url = URL(string: urlString) else { return .failure(NetworkError.invalidURL) } let (data, response) = URLSession.shared.synchronousData(with: url) return .success(data) } switch fetchDataResult(from: "https://api.example.com/data") { case .success(let data): print("Data received: \(data)") case .failure(let error): print("Error: \(error)") }
最佳实践:
- 使用枚举定义清晰的错误类型
- 为错误添加关联值提供更多信息
- 使用
try?处理可恢复的错误 - 使用
defer确保资源正确释放 - 在适当的地方使用
Result类型