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 错误处理代码。

相关推荐
2501_9159184110 小时前
iOS WebView 调试实战 localStorage 与 sessionStorage 同步问题全流程排查
android·ios·小程序·https·uni-app·iphone·webview
天下无贼!14 小时前
【样式效果】Vue3实现仿制iOS按钮动态效果
前端·css·vue.js·ios
捡芝麻丢西瓜14 小时前
iOS 异步任务 之 内存隔离
前端·ios
咕噜企业签名分发-淼淼14 小时前
苹果app应用ipa文件程序开发后如何运行到苹果iOS真机上测试?
ios
lzhdim21 小时前
iOS 26 公测版定了,预计下周发布!
macos·ios·objective-c·cocoa
杂雾无尘1 天前
解决 Xcode 烦人错误:"Build input file cannot be found" 一招搞定!
ios·swift·客户端
二流小码农2 天前
鸿蒙开发:弹出库更新至1.2.2版本,新增模态页面弹出
android·ios·harmonyos
水木姚姚2 天前
图书管理软件iOS(iPhone)
macos·ios·iphone·xcode·swift
tangbin5830852 天前
iOS 的 OC 语言:二进制数据处理与技巧
ios·objective-c