Swift - 错误处理



错误处理是管理和响应程序执行期间发生的意外情况的过程。错误可能由于各种原因发生,例如硬件问题、逻辑错误、意外的用户输入等。

Swift 为在运行时捕获、抛出和处理可恢复错误提供了良好的支持。错误处理的主要目标是

  • 检测错误 - 识别程序中错误发生的位置和类型。

  • 报告错误 - 向开发人员或最终用户报告错误的详细信息。

  • 处理错误 - 对发生的错误采取适当的措施,这可能包括提供错误消息、记录调试信息或实施恢复策略。

现在,在本文中,我们将讨论 Swift 如何表示、传播和处理错误。

Swift 中如何表示错误?

在 Swift 中,错误通过使用符合 Error 协议的类型来表示。Error 协议是空的,这意味着它没有任何需要实现的特定方法和属性,而是允许我们通过定义符合 Error 协议的新类型来创建自己的自定义错误类型。

表示错误的最佳方法是枚举。它将所有相关的错误条件与关联值和有关错误行为的信息分组。

示例

以下 Swift 示例将展示如何表示错误。

enum MyNewError: Error {
   case invalidInput
   case fileNotFound
   case networkError
   // Add more cases if you require
}

在 Swift 中抛出错误

在 Swift 中,抛出错误意味着当函数或方法检测到某些意外情况阻止其以正常方式执行时,它会抛出一个错误,表明发生了某些意外情况。它还有助于处理错误。我们可以借助throw语句抛出错误。

语法

以下是抛出错误的语法:

throw enumerationName.error

示例

以下 Swift 示例将展示如何抛出错误。

throw MyNewError.fileNotFound

使用抛出函数传播错误

我们可以从抛出函数传播错误。抛出函数是用 throw 关键字标记的函数。在 Swift 中,函数、方法或初始化器可以抛出错误。当函数、方法或初始化器遇到错误时,它们可以在其声明部分的参数之后和返回箭头(->)之前使用 throws 关键字。

只有抛出函数才能传播错误。如果在非抛出函数内部发生错误,则必须在该函数内部处理该错误。

语法

以下是抛出函数的语法:

func functionName(parameterList) throws -> ReturnType

示例

以下 Swift 程序将展示如何使用抛出函数抛出错误。

enum MyNewError: Error {
   case invalidInput
   case fileNotFound
   case networkError
}

// Throwing Function 
func processData(_ enterValue: String) throws {
   guard !enterValue.isEmpty else {
      throw MyNewError.invalidInput
   }
}

// Handling errors
do {

   // Calling throwing function
   try processData("")
   print("Successful")
} catch MyNewError.invalidInput {
   print("Invalid input")
} catch {
   print("Unexpected error occurred: \(error)")
}

输出

它将产生以下输出:

Invalid input

禁用错误传播

我们可以借助try!关键字禁用错误传播。当我们确信错误在运行时不会发生并且可以简化错误处理代码时,这很有用。但是,在使用 try! 关键字时要小心,如果发生错误,我们的程序将在运行时崩溃。

示例

Swift 程序演示如何禁用错误传播。

// Set of errors
enum myNewError: Error {
   case divisionByZero
   case invalidInput
}

// Throwing function
func divideNum(_ dividend: Int, by divisor: Int) throws -> Int {
   guard divisor != 0 else {
      throw myNewError.divisionByZero
   }

   return dividend / divisor
}

// Here we're sure that the divisor is not zero, 
// so we use try! to disable error propagation.
let output = try! divideNum(10, by: 2)

print(output)
输出

它将产生以下输出:

5

使用 Do-Catch 处理错误

在 Swift 中,我们可以借助do-catch语句处理错误。它使我们的代码更健壮,并允许我们为各种错误提供特定的错误处理逻辑。在 do-catch 语句中,do块包含可能抛出错误的代码,而 catch 块处理 do 块中发生的特定错误。

并非 do 子句抛出的所有错误都由 catch 子句处理。如果没有任何 catch 子句处理发生的错误,则该错误将传播到周围的范围,并且周围的范围将处理传播的错误。如果错误传播到顶级范围而未进行处理,我们将得到运行时错误。

在非抛出函数中,错误由封闭的 do-catch 语句处理,而在抛出函数中,错误由封闭的 do-catch 语句或调用方处理。

语法

以下是 do-catch 语句的语法:

do
{
   try<expression>
} catch <pattern1>{
   // statement
} catch <pattern2>{
   // statement
} catch <pattern3>, <pattern4> where <condition>{
   // statement
} catch {
   //statement
   // catch clause without pattern can match any error
}

示例

Swift 程序演示如何使用 do-catch 块处理错误。

// Set of errors
enum myNewError: Error {
   case divisionByZero
   case invalidInput
}

// Throwing function
func divideNum(_ dividend: Int, by divisor: Int) throws -> Int {
   guard divisor != 0 else {
      throw myNewError.divisionByZero
   }
   return dividend / divisor
}

// Handling error using do-catch statement
do {
   let result = try divideNum(10, by: 0)
   print("Result of division: \(result)")
} catch myNewError.divisionByZero {
   print("Found Error: Cannot divide by zero.")
} catch myNewError.invalidInput {
   print("Found Error: Input is not valid.")
} catch {
   print("An unexpected error occurred: \(error)")
}

输出

它将产生以下输出:

Found Error: Cannot divide by zero.

在 Swift 中将错误转换为可选值

要将错误转换为可选值,我们可以使用 try?。try?返回一个可选类型结果。如果在评估 try? 表达式时抛出错误,则 try? 表达式将返回 nil,否则,它将返回包含结果的可选类型。当我们希望在没有有关错误的任何其他信息的情况下优雅地处理错误时,此方法很有用。

示例

Swift 程序演示如何将错误转换为可选值。

// Set of errors
enum myNewError: Error {
   case divisionByZero
   case invalidInput
}

// Throwing function
func divideNum(_ dividend: Int, by divisor: Int) throws -> Int {
   guard divisor != 0 else {
      throw myNewError.divisionByZero
   }

   return dividend / divisor
}

// Handling error using do-catch statement
do {

   // Using try? to convert errors to optional values
   let output1 = try? divideNum(21, by: 3)
   let output2 = try? divideNum(10, by: 0)
    
   // Checking if the operation was successful using optional binding
   if let res = output1 {
      print("Result of division: \(res)")
   } else {
      print("Found Error")
   }

   if let res = output2 {
      print("Result of division: \(res)")
   } else {
      print("Found Error")
   }
} catch {

   // Handling other errors if available
   print("Found Error: \(error)")
}

输出

它将产生以下输出:

Result of division: 7
Found Error
广告