错误处理 #
一、错误处理概述 #
Swift提供了强大的错误处理机制,用于响应和处理运行时错误。
1.1 错误处理方式 #
- 抛出错误(throw)
- 捕获错误(try-catch)
- 传播错误(rethrows)
- 可选值处理(try?)
二、Error协议 #
2.1 定义错误类型 #
swift
enum NetworkError: Error {
case noConnection
case timeout
case serverError(Int)
case invalidURL
}
enum ValidationError: Error {
case emptyInput
case invalidLength
case invalidFormat
}
2.2 关联值错误 #
swift
enum FileError: Error {
case fileNotFound(path: String)
case permissionDenied
case readError(description: String)
}
func readFile(at path: String) throws -> String {
throw FileError.fileNotFound(path: path)
}
三、抛出错误 #
3.1 throw关键字 #
swift
func divide(_ a: Int, by b: Int) throws -> Int {
guard b != 0 else {
throw NSError(domain: "DivisionError", code: -1, userInfo: [NSLocalizedDescriptionKey: "除数不能为零"])
}
return a / b
}
3.2 自定义错误 #
swift
enum DivisionError: Error, LocalizedError {
case divisionByZero
var errorDescription: String? {
switch self {
case .divisionByZero:
return "除数不能为零"
}
}
}
func divide(_ a: Int, by b: Int) throws -> Int {
guard b != 0 else {
throw DivisionError.divisionByZero
}
return a / b
}
四、捕获错误 #
4.1 do-catch语句 #
swift
do {
let result = try divide(10, by: 0)
print(result)
} catch {
print("错误: \(error)")
}
4.2 多catch块 #
swift
enum NetworkError: Error {
case noConnection
case timeout
case serverError(Int)
}
func fetchData() throws -> Data {
throw NetworkError.serverError(500)
}
do {
let data = try fetchData()
print(data)
} catch NetworkError.noConnection {
print("无网络连接")
} catch NetworkError.timeout {
print("请求超时")
} catch NetworkError.serverError(let code) {
print("服务器错误: \(code)")
} catch {
print("未知错误: \(error)")
}
4.3 try?和try! #
swift
func divide(_ a: Int, by b: Int) throws -> Int {
guard b != 0 else {
throw DivisionError.divisionByZero
}
return a / b
}
let result1 = try? divide(10, by: 2)
print(result1 ?? 0)
let result2 = try? divide(10, by: 0)
print(result2 ?? 0)
let result3 = try! divide(10, by: 2)
print(result3)
五、错误传播 #
5.1 throws函数 #
swift
func validateInput(_ input: String?) throws -> String {
guard let input = input, !input.isEmpty else {
throw ValidationError.emptyInput
}
guard input.count >= 3 else {
throw ValidationError.invalidLength
}
return input
}
func processInput(_ input: String?) throws {
let validInput = try validateInput(input)
print("处理输入: \(validInput)")
}
5.2 rethrows #
swift
func process<T>(_ value: T, using transform: (T) throws -> T) rethrows -> T {
return try transform(value)
}
let result = try process(5) { value in
guard value > 0 else {
throw NSError(domain: "", code: -1)
}
return value * 2
}
六、Result类型 #
6.1 基本用法 #
swift
enum NetworkError: Error {
case noConnection
case serverError
}
func fetchData(completion: @escaping (Result<Data, NetworkError>) -> Void) {
let success = Bool.random()
if success {
completion(.success(Data()))
} else {
completion(.failure(.serverError))
}
}
fetchData { result in
switch result {
case .success(let data):
print("成功: \(data)")
case .failure(let error):
print("失败: \(error)")
}
}
6.2 Result方法 #
swift
let result: Result<Int, Error> = .success(42)
let mapped = result.map { $0 * 2 }
print(mapped)
let flatMapped = result.flatMap { value in
return .success(value + 10)
}
print(flatMapped)
do {
let value = try result.get()
print(value)
} catch {
print(error)
}
6.3 实际应用 #
swift
struct User: Decodable {
let id: Int
let name: String
}
func fetchUser(id: Int) -> Result<User, Error> {
let json = """
{"id": 1, "name": "张三"}
"""
guard let data = json.data(using: .utf8) else {
return .failure(NSError(domain: "", code: -1))
}
do {
let user = try JSONDecoder().decode(User.self, from: data)
return .success(user)
} catch {
return .failure(error)
}
}
let result = fetchUser(id: 1)
switch result {
case .success(let user):
print(user.name)
case .failure(let error):
print(error)
}
七、defer语句 #
7.1 基本用法 #
swift
func processFile() throws {
print("开始处理")
defer {
print("清理资源")
}
print("处理中...")
if Bool.random() {
throw NSError(domain: "", code: -1)
}
print("处理完成")
}
do {
try processFile()
} catch {
print("捕获错误")
}
7.2 多个defer #
swift
func multipleDefer() {
defer { print("第一个defer") }
defer { print("第二个defer") }
defer { print("第三个defer") }
print("函数体")
}
multipleDefer()
八、实际应用 #
8.1 网络请求 #
swift
enum APIError: Error {
case invalidURL
case noData
case decodingError
}
class APIClient {
func request<T: Decodable>(url: URL) async throws -> T {
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw APIError.noData
}
do {
return try JSONDecoder().decode(T.self, from: data)
} catch {
throw APIError.decodingError
}
}
}
8.2 文件操作 #
swift
enum FileError: Error {
case fileNotFound
case readError
case writeError
}
func readTextFile(at path: String) throws -> String {
guard let data = FileManager.default.contents(atPath: path) else {
throw FileError.fileNotFound
}
guard let text = String(data: data, encoding: .utf8) else {
throw FileError.readError
}
return text
}
func writeTextFile(at path: String, content: String) throws {
guard let data = content.data(using: .utf8) else {
throw FileError.writeError
}
try data.write(to: URL(fileURLWithPath: path))
}
8.3 表单验证 #
swift
enum FormError: Error {
case emptyField(String)
case invalidEmail
case passwordTooShort
case passwordsDoNotMatch
}
struct FormData {
var email: String
var password: String
var confirmPassword: String
}
func validateForm(_ data: FormData) throws -> Bool {
guard !data.email.isEmpty else {
throw FormError.emptyField("邮箱")
}
guard data.email.contains("@") else {
throw FormError.invalidEmail
}
guard data.password.count >= 8 else {
throw FormError.passwordTooShort
}
guard data.password == data.confirmPassword else {
throw FormError.passwordsDoNotMatch
}
return true
}
九、总结 #
本章学习了Swift错误处理:
- Error协议:定义错误类型
- throw:抛出错误
- do-catch:捕获错误
- Result:封装结果
最佳实践:
- 使用枚举定义错误
- 提供有意义的错误信息
- 合理使用try?和try!
- 使用defer清理资源
下一章,我们将学习实践应用!
最后更新:2026-03-26