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
廣告