iOS 控制流 之 错误传播

在 Swift 中,throwsrethrowsneverNever 类型)是与错误处理相关的关键概念,它们分别用于不同场景下的错误传播和控制流。以下是它们的详细对比和用法解析:


1. throws:声明可能抛出错误的函数

作用

  • 标记一个函数、方法或闭包可能抛出错误(Error 协议类型)。
  • 调用方必须使用 trydo-catchtry?/try! 处理错误。

语法

swift 复制代码
func mightFail() throws -> Int {
    // 可能抛出错误的代码
    throw SomeError.example
    return 42
}

调用方式

swift 复制代码
// 方式 1: do-catch
do {
    let result = try mightFail()
    print(result)
} catch {
    print("Error: (error)")
}
 
// 方式 2: try? (返回 Optional)
if let result = try? mightFail() {
    print(result)
}
 
// 方式 3: try! (强制解包,崩溃风险)
let result = try! mightFail() // 如果抛出错误,程序崩溃

适用场景

  • 任何可能因外部条件(如网络请求、文件读写)失败的函数。
  • 需要明确告知调用方可能出错的接口。

2. rethrows:重新抛出错误的函数

作用

  • 标记一个高阶函数 (接受闭包作为参数的函数)可能抛出错误,但错误实际来自闭包本身
  • 函数本身不直接抛出错误,只是将闭包中的错误向上传递。
  • 编译器会检查闭包是否可能抛出错误,如果闭包不抛出错误,则调用方也无需处理错误。

语法

swift 复制代码
func process(_ action: () throws -> Void) rethrows {
    try action() // 仅重新抛出闭包中的错误
}

调用方式

swift 复制代码
// 闭包抛出错误时,需用 try 调用 process
do {
    try process {
        throw SomeError.example
    }
} catch {
    print("Error: (error)")
}
 
// 闭包不抛出错误时,无需 try
process {
    print("No error here")
}

throws 的区别

特性 throws rethrows
错误来源 函数内部可能抛出错误 错误仅来自闭包参数
调用要求 调用方必须处理错误(无论闭包是否抛出) 仅当闭包抛出错误时,调用方需处理错误
典型场景 直接操作可能失败的资源(如文件读写) 高阶函数(如 mapforEach 的变体)

示例:rethrows 的实际应用

swift 复制代码
// 高阶函数:仅当闭包抛出错误时,才需要 try
func retry<T>(times: Int, _ action: () throws -> T) rethrows -> T {
    for _ in 0..<times {
        do {
            return try action()
        } catch {
            continue
        }
    }
    throw SomeError.maxRetriesExceeded
}
 
// 调用方式 1:闭包抛出错误
do {
    let result = try retry(times: 3) {
        throw SomeError.example
    }
} catch {
    print("Failed after retries: (error)")
}
 
// 调用方式 2:闭包不抛出错误
let success = try retry(times: 3) {
    return "Success" // 无需 catch
}

3. Never:表示永不返回的错误类型

作用

  • Never 是 Swift 的"底部类型"(Bottom Type),表示函数永远不会正常返回(要么无限执行,要么抛出错误/终止程序)。
  • 常用于标记致命错误无限循环的场景。

语法

swift 复制代码
func crashAndBurn() -> Never {
    fatalError("Something went wrong!") // 终止程序
}

throws 的关系

  • 如果函数返回 Never,则它必须抛出错误或终止程序(不能正常返回)。
  • 编译器会强制检查所有代码路径是否满足 Never 的语义。

示例

swift 复制代码
// 1. 抛出错误(满足 Never 的语义)
func impossible() -> Never {
    throw SomeError.criticalFailure
}
 
// 2. 无限循环(也满足 Never 的语义)
func infiniteLoop() -> Never {
    while true {}
}
 
// 3. 调用 Never 函数时,编译器知道后续代码不可达
func test() {
    impossible() // 调用后,编译器认为后续代码不会执行
    print("This line will never run") // ❌ 编译警告:Unreachable code
}

适用场景

  • 标记不可恢复的错误(如 fatalErrorpreconditionFailure)。
  • 实现无限循环或事件循环(如游戏主循环)。

4. 总结对比

关键字 作用 典型场景
throws 声明函数可能抛出错误,调用方必须处理 文件读写、网络请求等可能失败的操作
rethrows 声明高阶函数可能重新抛出闭包中的错误,调用方仅在闭包抛出错误时需处理 mapforEach 的变体,如 retry
Never 表示函数永不返回(抛出错误或终止程序),编译器强制检查代码路径 fatalError、无限循环、不可恢复错误

5. 最佳实践

  1. 优先使用 throws

    • 对于可能因外部条件失败的函数,明确标记 throws 以提高代码安全性。

    • 示例:

      swift 复制代码
      func readFile(_ path: String) throws -> String {
          guard let content = try? String(contentsOfFile: path) else {
              throw FileError.notFound
          }
          return content
      }
  2. 谨慎使用 rethrows

    • 仅在高阶函数中需要重新抛出闭包错误时使用,避免滥用。

    • 示例:

      swift 复制代码
      func safeExecute(_ action: () throws -> Void) rethrows {
          print("Starting action...")
          try action()
          print("Action completed.")
      }
  3. 避免滥用 Never

    • 仅在确实需要终止程序或实现无限循环时使用。

    • 示例:

      swift 复制代码
      func validateInput(_ input: String) -> Never {
          precondition(input.count > 0, "Input cannot be empty!")
      }

通过合理使用这些关键字,可以写出更安全、更清晰的 Swift 错误处理代码。

相关推荐
zhensherlock1 小时前
Protocol Launcher 系列:App Store 精准引流与应用推广
javascript·macos·ios·typescript·iphone·mac·ipad
for_ever_love__5 小时前
Objective-C学习 NSDictionary,NSMutableDictionary 功能详解
开发语言·学习·ios·objective-c
for_ever_love__5 小时前
Objective-C学习 协议和委托
开发语言·学习·ios·objective-c
2501_915909061 天前
不用越狱就看不到 iOS App 内部文件?使用 Keymob 查看和导出应用数据目录
android·ios·小程序·https·uni-app·iphone·webview
@大迁世界1 天前
液态玻璃屏正在侵蚀你的电池
macos·ios·objective-c·cocoa
pop_xiaoli1 天前
【iOS】类与对象底层
macos·ios·objective-c·cocoa·xcode
sp42a1 天前
NativeScript iOS 平台开发技巧
ios·nativescript·app 开发
2501_915921431 天前
常用iOS性能测试工具大全及使用指南
android·测试工具·ios·小程序·uni-app·cocoa·iphone
for_ever_love__1 天前
Objecgtive-C学习实例对象,类对象, 元类对象与 isa指针
c语言·学习·ios
一招定胜负1 天前
视频转写+LLM分析:课堂录音自动化处理实现
macos·ios·xcode