关键字 — throws
This article is extracted from the chat log with AI. Please identify it with caution.

Swift 错误处理:throwthrowstry 的完整指南 #

1. 核心概念 #

Swift 错误处理三要素 #

关键字/机制作用阶段
throws声明函数可能抛出错误函数声明
throw主动抛出错误实例函数实现
try调用可能抛出错误的函数函数调用
do-catch捕获和处理错误错误处理

2. 函数声明与 throws #

基本语法 #

func functionName(parameters) throws -> ReturnType {
    // 实现可能抛出错误的代码
}

关键特征 #

  • throws 关键字的位置:在参数列表之后,返回类型之前
  • 可与其他修饰符组合:
    async throws -> Data      // 异步+可能抛出错误
    mutating throws -> Void  // 可变方法+可能抛出错误
    

返回值类型示例 #

声明形式含义
func a() -> String返回 String,不抛出错误
func b() throws -> String返回 String,可能抛出错误
func c() throws没有返回值,可能抛出错误(等价于 throws -> Void

3. 错误抛出 (throw) #

错误类型要求 #

必须实现 Error 协议:

enum NetworkError: Error {
    case invalidURL
    case timeout(duration: Int)
    case serverError(code: Int)
}

struct ParsingError: Error {
    let line: Int
    let column: Int
}

抛出方式 #

func validateInput(_ input: String) throws {
    guard !input.isEmpty else {
        throw ValidationError.emptyInput
    }
    
    guard input.count >= 8 else {
        throw ValidationError.tooShort(minLength: 8)
    }
}

4. 错误捕获 (try) #

try 的三重形态 #

形式行为返回值类型错误处理方式
try标准形式原类型必须用 do-catch
try?忽略错误Optional错误时返回 nil
try!强制解包(危险)非可选类型错误时崩溃

标准捕获模式 #

do {
    let data = try parseData(rawInput)
    let result = try process(data)
    print("Success: \(result)")
} catch ValidationError.emptyInput {
    print("Error: Input cannot be empty")
} catch let ValidationError.tooShort(minLength) {
    print("Error: Need at least \(minLength) characters")
} catch {
    print("Unexpected error: \(error)")
}

5. 返回值与错误的关系 #

返回值的存在性 #

// 可能返回 String 或抛出错误
func fetchString() throws -> String {
    if successCondition {
        return "Data"
    } else {
        throw FetchError.failed
    }
}

// 没有返回值,只有成功/失败
func saveToDisk() throws {
    guard hasPermission else {
        throw DiskError.permissionDenied
    }
    // 保存操作...
}

特殊返回值模式 #

// 返回 Optional,错误时返回 nil
func safeFetch() -> String? {
    return try? dangerousFetch()
}

// 返回 Result 类型
func modernFetch() -> Result<String, Error> {
    do {
        let value = try dangerousFetch()
        return .success(value)
    } catch {
        return .failure(error)
    }
}

6. 高级场景与最佳实践 #

链式错误处理 #

func complexOperation() throws -> FinalResult {
    let rawData = try fetchData()          // 可能抛出 NetworkError
    let parsed = try parse(rawData)        // 可能抛出 ParsingError
    return try transform(parsed)           // 可能抛出 TransformationError
}

// 统一处理所有可能的错误
do {
    let result = try complexOperation()
} catch let error as NetworkError {
    // 处理网络错误
} catch let error as ParsingError {
    // 处理解析错误
} catch {
    // 其他错误
}

异步错误处理 #

func asyncFetch() async throws -> Data {
    let (data, _) = try await URLSession.shared.data(from: url)
    return data
}

Task {
    do {
        let data = try await asyncFetch()
        // 使用数据
    } catch {
        // 处理错误
    }
}

重新抛出 (rethrows) #

func mapValues<T>(_ transform: (Element) throws -> T) rethrows -> [T] {
    var result = [T]()
    for element in self {
        result.append(try transform(element))
    }
    return result
}

// 使用示例
let numbers = [1, 2, 3]
let strings1 = numbers.mapValues { String($0) }        // 不需要 try
let strings2 = numbers.mapValues { throw SomeError() } // 需要 try

7. 常见误区与调试技巧 #

典型错误模式 #

  1. 错误的位置错误

    // ❌ 错误:throws 应该在返回类型前
    func wrong() -> throws String { ... }
    
    // ✅ 正确
    func correct() throws -> String { ... }
    
  2. 忽略必要错误处理

    // ❌ 编译错误:未处理可能的错误
    let data = parseData(rawInput)
    
    // ✅ 正确处理
    let data = try? parseData(rawInput)
    
  3. 过度使用 try!

    // ❌ 危险:可能导致崩溃
    let data = try! parseData(untrustedInput)
    
    // ✅ 安全处理
    if let data = try? parseData(input) {
        // 处理数据
    }
    

调试建议 #

  1. 使用 catch 块打印错误堆栈:

    do {
        try riskyOperation()
    } catch {
        print("Error occurred: \(error)")
        dump(error)  // 查看完整错误信息
        Thread.callStackSymbols.forEach { print($0) }  // 打印调用堆栈
    }
    
  2. 断点设置:

    • 在 Xcode 中添加 Exception Breakpoint
    • 使用条件断点捕获特定错误类型
  3. 错误传播跟踪:

    func debugTry<T>(_ expression: () throws -> T) -> T {
        do {
            return try expression()
        } catch {
            print("Error propagated: \(error)")
            throw error  // 继续传递错误
        }
    }
    
    // 使用示例
    let result = try debugTry { try parseData(input) }
    

总结表格 #

场景推荐模式应避免的模式
简单错误处理do-catch 基本块忽略 try
可选值处理try? + Optional Binding强制解包 try!
错误传播rethrows + 高阶函数多层嵌套 do-catch
异步操作async throws + Task混合回调与错误处理
单元测试XCTAssertThrowsError不验证错误条件

通过本指南,您应该能够:

  1. 正确声明和使用抛出错误的函数
  2. 合理选择 trytry?try!
  3. 设计清晰的错误传播路径
  4. 编写健壮的异步错误处理代码
  5. 避免常见错误处理陷阱

建议结合具体项目需求选择错误处理策略,在代码安全性和简洁性之间找到最佳平衡点。

本文共 1329 字,创建于 Apr 1, 2025
相关标签: Xcode, Swift, ByAI