# Error handler

แม้ว่าโดยทั่วไปฟังก์ชั่นใน Swift หรือจากไลบารีจะไม่ค่อยมี Error เกิดขึ้น แต่ในบางครั้ง บางฟังก์ชั่นก็มีการส่ง Error ออกมา ซึ่งเราสามารถดูได้จาก signature ของฟังก์ชั่นนั้น ฟังก์ชั่นที่สามารถส่ง Error ออกมาได้ จะมี keyword `throws` หน้าตาประมาณนี้

```swift
func canThrowErrors() throws -> String
```

เมื่อฟังก์ชั่นสามารถที่จะ throw error ออกมาได้ ฝั่งที่เรียกใช้งานฟังก์ชั่นจึงต้องเขียนรองรับการส่ง error ออกมาด้วย `do catch` โดยจะต้องมี `try` อยู่ที่หน้าฟังก์ชั่นที่ throw error ได้

```swift
do {
    let user = try decode()
    print(user.name)
} catch {
    print(error)
}
```

จากตัวอย่างโค้ด ฟังก์ชั่น decode สามารถ throw error ออกมา จึงต้องครอบด้วย `do catch` และใส่ `try` ขณะเรียก decode

ในบล๊อก `catch` จะได้ตัวแปร `error` มาโดยอัตโนมัติ

ในกรณีที่ต้องการ handle แต่ละ Error แยกกัน สามารถ catch แยกกันได้

```swift
enum VendingMachineError: Error {
    case invalidSelection
    case outOfStock
    case insufficientFunds(coinsNeeded: Int)
}

func buyFavoriteSnack() throws {
    throw VendingMachineError.insufficientFunds(coinsNeeded: 9)
}

do {
    try buyFavoriteSnack()
} catch VendingMachineError.invalidSelection  {
    print("invalid selection")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {
    print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
} catch {
    print(error)
}
```

ในบางครั้งเราอาจจะเห็นโค้ดแบบนี้

```swift
let user = try? decode()
```

คือไม่ใส่ `do catch` ในกรณีนี้ `user` จะกลายเป็น optional ไปด้วย และถ้าฟังก์ชั่น decode throw error ออกมา `user` จะเป็น `nil`&#x20;

ในทางกลับกัน `try!` ก็สามารถใช้งานได้เช่นกัน ถ้าไม่ error ผลลัพธ์ที่ได้จะไม่ใช่ optional แต่ถ้ามี error แอปเราก็จะ crash

**The guard Statement**

ในบางครั้งการทำ optional binding และการตรวจสอบเงื่อนไขจะทำให้เรามี `nested if` ซ้อนเข้าไปเรื่อย ทำให้เราอ่านยาก

```swift
func isValid(text: String?) -> Bool {
    if let text = text {
        if text.count != 5 {
            return false
        }
        if !text.hasPrefix("W") {
            return false
        }
        print(text)
        return true
    }
    return false
}
```

swift จึงมี `guard` ให้เราใช้ ซึ่งจะทำหน้าที่คล้าย ๆ กับตรงข้ามกับ `if` แต่ในบล๊อก guard จะต้อง return ทุกครั้งที่ทำเสร็จ

```swift
func isValid(text: String?) -> Bool {
    guard let text = text, text.count == 5, text.hasPrefix("W") else {
        return false
    }
    print(text)
    return true
}
```

จากตัวอย่าง guard จะทำ optional binding และ ตรวจสอบเงื่อนไข ถ้าทั้งหมดเป็นจริง บล๊อก guard จะไม่ทำงานและรันลงมาต่อที่บรรทัด 5 ตัวแปร text จะไม่ใช่ optional แล้ว&#x20;

แต่ถ้าไม่สามารถ unwrap text ได้ หรือเงื่อนไขไม่เป็นความจริง บล๊อก guard จะทำงานและ return false ออกไป


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://pakornpat.gitbook.io/ios-app/swift/error-handler.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
