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

相关推荐
tangweiguo030519875 小时前
SwiftUI布局完全指南:从入门到精通
ios·swift
T1an-19 小时前
最右IOS岗一面
ios
坏小虎12 小时前
Expo 快速创建 Android/iOS 应用开发指南
android·ios·rn·expo
光影少年13 小时前
Android和iOS原生开发的基础知识对RN开发的重要性,RN打包发布时原生端需要做哪些配置?
android·前端·react native·react.js·ios
北京自在科技13 小时前
Find My 修复定位 BUG,AirTag 安全再升级
ios·findmy·airtag
Digitally14 小时前
如何不用 USB 线将 iPhone 照片传到电脑?
ios·电脑·iphone
Sim14801 天前
iPhone将内置本地大模型,手机端AI实现0 token成本时代来临?
人工智能·ios·智能手机·iphone
Digitally1 天前
如何将 iPad 上的照片传输到 U 盘(4 种解决方案)
ios·ipad
报错小能手1 天前
ios开发方向——swift并发进阶核心 @MainActor 与 DispatchQueue.main 解析
开发语言·ios·swift
LcGero1 天前
Cocos Creator 业务与原生通信详解
android·ios·cocos creator·游戏开发·jsb