Potato
μ•ˆλ…•ν•˜μ„Έμš”, κ°μž‘λ‹ˆλ‹€?πŸ₯” ^___^ 😺 github λ°”λ‘œκ°€κΈ° πŸ‘‰πŸ»

Swift/Swift Documents

[Swift] 곡식 λ¬Έμ„œ 정리 (17) Error Handling (μ—λŸ¬ 처리 방법 4가지, do-catch, throws ꡬ문)

감자 πŸ₯” 2022. 3. 8. 23:48
λ°˜μ‘ν˜•

μ•ˆλ…•ν•˜μ„Έμš”, κ°μžμž…λ‹ˆλ‹€. μ˜€λŠ˜μ€ μ—λŸ¬λ₯Ό ν•Έλ“€λ§ν•˜λŠ” 방법에 λŒ€ν•΄μ„œ μ•Œμ•„λ³΄λ„λ‘ ν• κ²Œμš”. swift κ³΅μ‹λ¬Έμ„œ 17번째 μ±•ν„°μ—μš”! 일주일에 μ•½3~5κ°œμ”© κΎΈμ€€νžˆ μ •λ¦¬ν•˜λ‹€λ³΄λ‹ˆ 벌써 17개λ₯Ό ν–ˆλ„€μš” γ…Žγ…Ž ν•˜λ©΄μ„œ λͺ¨λ“  κ°œλ…μ΄ μ™„λ²½ν•˜κ²Œ μž‘νžˆμ§„ μ•Šμ•˜μ§€λ§Œ, ν•˜λ‚˜ν•˜λ‚˜ λͺ¨λ₯΄λ˜ 뢀뢄을 μ•Œκ²Œλ˜κ³  λ†“μ³€λ˜ 뢀뢄도 λ‹€μ‹œ λ³΄κ²Œλ˜λŠ” 것 κ°™μ•„μš”. 

기본적으둜 3νšŒλ…μ •λ„ ν•˜λ©΄, λ©΄μ ‘ λŒ€λΉ„κΉŒμ§€ 되겟죠?! γ…Žγ…Žγ…Žγ…Ž ν™”μ΄νŒ…μž…λ‹ˆλ‹€ λͺ¨λ‘!

Swift document chap.17 Error Handling λ³΄λŸ¬κ°€κΈ°

 

Error Handling — The Swift Programming Language (Swift 5.6)

Error Handling Error handling is the process of responding to and recovering from error conditions in your program. Swift provides first-class support for throwing, catching, propagating, and manipulating recoverable errors at runtime. Some operations aren

docs.swift.org


Error Handling

ν”„λ‘œκ·Έλž¨ μ‹€ν–‰ μ‹œ μ—λŸ¬κ°€ λ°œμƒν•˜λ©΄ κ·Έ 상황에 λŒ€ν•΄ μ μ ˆν•œ μ²˜λ¦¬κ°€ ν•„μš”ν•œλ°, 이런 처리λ₯Ό “Error handling”이라고 ν•œλ‹€.

Swiftμ—μ„œλŠ” λŸ°νƒ€μž„ μ—λŸ¬κ°€ λ°œμƒν•˜λ©΄, μ—λŸ¬λ₯Ό μ²˜λ¦¬ν•˜κΈ° μœ„ν•΄ μ—λŸ¬μ˜ λ°œμƒ (throwing) , 감지(catching), μ „νŒŒ(propagating), μ‘°μž‘(mainpulating)을 μ§€μ›ν•˜λŠ” 일급 클래슀λ₯Ό μ œκ³΅ν•œλ‹€.

μ–΄λ–€ λͺ…령은 μ™„μ „νžˆ μ‹€ν–‰λ˜λŠ” 것이 보μž₯λ˜μ§€ μ•ŠλŠ” 경우, μ˜΅μ…”λ„μ„ μ‚¬μš©ν•˜μ—¬ μ—λŸ¬κ°€ λ°œμƒν•΄ 값이 μ—†λ‹€κ³  nil 둜 ν‘œμ‹œν•  수 μžˆλ‹€. ν•˜μ§€λ§Œ μ–΄λ–€ μ’…λ₯˜μ˜ μ—λŸ¬κ°€ λ°œμƒν–ˆλŠ”μ§€λŠ” μ•Œ 수 μ—†λ‹€. μ΄λŸ΄λ•ŒλŠ” ꡬ체적으둜 λ°œμƒν•œ μ—λŸ¬λ₯Ό 확인할 수 μžˆμ–΄μ•Ό μ½”λ“œλ₯Ό μž‘μ„±ν•˜λŠ” μ‚¬λžŒμ΄ μ—λŸ¬μ— κ²½μš°μ— λ”°λ₯Έ μ μ ˆν•œ 처리λ₯Ό ν•  수 μžˆλ‹€.

Swiftμ—μ„œ μ—λŸ¬μ²˜λ¦¬λŠ” Cocoa의 NSError ν΄λž˜μŠ€μ™€ μƒν˜Έν˜Έν™˜ λ˜λŠ” μ—λŸ¬ 핸듀링 νŒ¨ν„΄μ„ μ‚¬μš©ν•œλ‹€.


 

μ—λŸ¬μ˜ ν‘œμ‹œμ™€ λ°œμƒ

Swiftμ—μ„œ μ—λŸ¬λŠ” Error ν”„λ‘œν† μ½œμ„ λ”°λ₯΄λŠ” νƒ€μž…μ˜ κ°’μœΌλ‘œ ν‘œν˜„λœλ‹€. λΉ„μ–΄μžˆλŠ” 이 ν”„λ‘œν† μ½œμ€ ν”„λ‘œν† μ½œμ„ λ”°λ₯΄λŠ” νƒ€μž…μ΄ μ—λŸ¬μ²˜λ¦¬λ₯Ό μœ„ν•΄ μ‚¬μš© 될 수 μžˆλ‹€λŠ” 것을 κ°€λ₯΄ν‚¨λ‹€.

Swift의 μ—΄κ±°ν˜•μ€ νŠΉλ³„νžˆ 이런 κ΄€λ ¨λœ μ—λŸ¬λ₯Ό Grouping ν•˜κ³  좔가적인 정보λ₯Ό μ œκ³΅ν•˜κΈ°μ— μ ν•©ν•˜λ‹€.

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

μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚΄μœΌλ‘œμ¨ 무언가 κΈ°λŒ€ν•˜μ§€ μ•Šμ•˜λ˜ λ™μž‘μ΄ λ°œμƒν–ˆκ³ , μž‘μ—…μ„ 계속 μˆ˜ν–‰ν•  수 μ—†λ‹€λŠ” 것을 μ•Œλ €μ€„ 수 μžˆλ‹€. μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚€κΈ° μœ„ν•΄ throw ꡬ문을 μ‚¬μš©ν•  수 μžˆλ‹€.

λ‹€μŒ μ½”λ“œλŠ” νŒλ§€κΈ°κΈ°μ—μ„œ 5개의 코인이 더 ν•„μš”ν•˜λ‹€λŠ” μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚¨λ‹€.

throw VendingMachineError.insufficientFunds(coinsNeeded: 5)

 

μ—λŸ¬ 처리

μ—λŸ¬κ°€ λ°œμƒν•˜λ©΄ νŠΉμ • μ½”λ“œμ˜μ—­μ΄ ν•΄λ‹Ή μ—λŸ¬λ₯Ό μ²˜λ¦¬ν•˜κ²Œ ν•΄μ•Όν•œλ‹€. 문제λ₯Ό ν•΄κ²°ν•˜κ±°λ‚˜, μš°νšŒν•  수 μžˆλŠ” 방법을 μ‹œλ„ν•˜κ±°λ‚˜, μ•„λ‹ˆλ©΄ μ‚¬μš©μžμ—κ²Œ μ‹€νŒ¨ 상황을 μ•Œλ¦¬λŠ” 것이 μ—λŸ¬ 처리의 방식이 될 수 μžˆλ‹€.

Swiftμ—μ„œλŠ” 4가지 μ—λŸ¬λ₯Ό μ²˜λ¦¬ν•˜λŠ” 방버이 μžˆλ‹€.

  1. Error propagation (μ—λŸ¬λ₯Ό μ „νŒŒ) (μ—λŸ¬κ°€ λ°œμƒν•œ ν•¨μˆ˜μ—μ„œ λ¦¬ν„΄κ°’μœΌλ‘œ μ—λŸ¬λ₯Ό λ°˜ν™˜ν•˜μ—¬ ν•΄λ‹Ή ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•œ μ½”λ“œμ—μ„œ μ—λŸ¬λ₯Ό μ²˜λ¦¬ν•˜λ„λ‘ ν•˜λŠ” 방법)
  2. do-catch ꡬ문을 μ‚¬μš©ν•˜λŠ” 방법
  3. μ˜΅μ…”λ„ 값을 λ°˜ν™˜ν•˜λŠ” 방법
  4. 였λ₯˜κ°€ λ°œμƒν•˜μ§€ μ•Šμ„ 것이라고 μ •μ˜ν•˜λŠ” 방법 (assert λ₯Ό μ‚¬μš©ν•˜μ—¬ κ°•μ œλ‘œ ν¬λž˜μ‰¬λ₯Ό λ°œμƒμ‹œν‚€λŠ” 방법)

ν•¨μˆ˜μ—μ„œ 였λ₯˜κ°€ λ°œμƒν•˜λ©΄ ν”„λ‘œκ·Έλž¨μ˜ 흐름이 λ³€κ²½λ˜κΈ° λ•Œλ¬Έμ— μ½”λ“œμ—μ„œ 였λ₯˜κ°€ λ°œμƒν•  수 μžˆλŠ” μœ„μΉ˜λ₯Ό λΉ λ₯΄κ²Œ 식별할 수 μžˆμ–΄μ•Ό ν•œλ‹€. μ½”λ“œμ—μ„œ μ΄λŸ¬ν•œ 였λ₯˜λ₯Ό μ‹λ³„ν•˜λ €λ©΄, try, try?, try! ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€.

 

1. Throw ꡬ문을 μ‚¬μš©ν•΄μ„œ μ—λŸ¬λ₯Ό μ „νŒŒν•˜κΈ° (propagating)

μ–΄λ–€ ν•¨μˆ˜, λ©”μ„œλ“œ, μƒμ„±μžκ°€ μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚¬ 수 μžˆλ‹€λŠ” 것을 μœ„ν•΄μ„œ throw ν‚€μ›Œλ“œλ₯Ό ν•¨μˆ˜ μ„ μ–ΈλΆ€μ˜ νŒŒλΌλ―Έν„° 뒀에 뢙일 수 μžˆλ‹€. throw ν‚€μ›Œλ“œλ‘œ ν‘œμ‹œλœ ν•¨μˆ˜λ₯Ό throwing func 라고 λΆ€λ₯Έλ‹€.λ§Œμ•½ ν•¨μˆ˜κ°€ 리턴값을 λͺ…μ‹œν–ˆλ‹€λ©΄, throw ν‚€μ›Œλ“œλŠ” 리턴값 ν‘œμ‹œ 기호 -> 전에 μ λŠ”λ‹€.

func canThrowErrors() throws -> String

func cannotThrowErrors() -> String

throwing function은 ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ μ—λŸ¬λ₯Ό λ§Œλ“€μ–΄μ„œ ν•¨μˆ˜κ°€ ν˜ΈμΆœν•œ 곳으둜 μ „λ‹¬ν•œλ‹€. throwing ν•¨μˆ˜λ§Œ μ—λŸ¬λ₯Ό 전달할 수 μžˆλ‹€. κ·ΈλŸ¬λ―€λ‘œ throwing ν•¨μˆ˜κ°€ μ•„λ‹Œ ν•¨μˆ˜μ—μ„œλŠ” μ—λŸ¬λ₯Ό λ‚΄λΆ€μ—μ„œ μ²˜λ¦¬ν•΄μ•Όν•œλ‹€.

struct Item {
    var price: Int
    var count: Int
}

class VendingMachine {
    var inventory = [
        "Candy Bar": Item(price: 12, count: 7),
        "Chips": Item(price: 10, count: 4),
        "Pretzels": Item(price: 7, count: 11)
    ]
    var coinsDeposited = 0

    func vend(itemNamed name: String) throws {
        guard let item = inventory[name] else {
            throw VendingMachineError.invalidSelection
        }

        guard item.count > 0 else {
            throw VendingMachineError.outOfStock
        }

        guard item.price <= coinsDeposited else {
            throw VendingMachineError.insufficientFunds(coinsNeeded: item.price - coinsDeposited)
        }

        coinsDeposited -= item.price

        var newItem = item
        newItem.count -= 1
        inventory[name] = newItem

        print("Dispensing \\(name)")
    }
}

μœ„ μ½”λ“œλŠ” VendingMachine ν΄λž˜μŠ€μ—μ„œ λ°œμƒν•  수 μžˆλŠ” 였λ₯˜λ₯Ό μ²˜λ¦¬ν•˜κΈ° μœ„ν•œ vend(itemNamed name: ) λ©”μ„œλ“œλ₯Ό 가진닀.

ν•΄λ‹Ή λ©”μ„œλ“œμ—μ„œλŠ” guard 문을 ν™œμš©ν•˜μ—¬ snack을 κ΅¬λ§€ν•˜λŠ” κ³Όμ •μ—μ„œ μ—λŸ¬κ°€ λ°œμƒν•˜λ©΄ ν•¨μˆ˜μ—μ„œ μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚€κ³  λΉ λ₯΄κ²Œ ν•¨μˆ˜λ₯Ό νƒˆμΆœ ν•  수 μžˆλ„λ‘ ν•œλ‹€ (early exit).

vend(itemNamed: ) λ©”μ„œλ“œλŠ” μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚€κΈ° λ•Œλ¬Έμ— 이 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” λ©”μ„œλ“œλŠ” λ°˜λ“œμ‹œ do-catch, try?, try! ꡬ문을 μ‚¬μš©ν•˜μ—¬ μ—λŸ¬λ₯Ό μ²˜λ¦¬ν•΄μ•Όν•œλ‹€.

let favoriteSnacks = [
    "Alice": "Chips",
    "Bob": "Licorice",
    "Eve": "Pretzels",
]

// buyFavoriteSnackν•¨μˆ˜λŠ” 주어진 μ‚¬λžŒμ˜ κ°€μž₯ μ’‹μ•„ν•˜λŠ” μŠ€λ‚΅μ΄ 무엇인지 ν™•μΈν•˜κ³  
// 그것을 vend λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ ꡬ맀λ₯Ό μ‹œλ„ν•˜λŠ” λ™μž‘μ„ μˆ˜ν–‰
func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
     let snackName = favoriteSnacks[person] ?? "Candy Bar"
     try vendingMachine.vend(itemNamed: snackName)
}

buyFavoriteSnack(person:vendingMaching: ) ν•¨μˆ˜μ—μ„œ vendingMachine μΈμŠ€ν„΄μŠ€μ˜ vend(itemNamed: ) λ©”μ„œλ“œμ—μ„œ μ—λŸ¬κ°€ λ°œμƒν•˜λ©΄ 이 μ—λŸ¬λŠ” buyFavoriteSnack ν•¨μˆ˜μ˜ 내뢀에 μ „νŒŒλœλ‹€. λ”°λΌμ„œ 이 ν•¨μˆ˜μ—μ„œ ν•΄λ‹Ή λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λ €λ©΄ try ν‚€μ›Œλ“œλ₯Ό ν•¨κ»˜ μ‚¬μš©ν•΄μ€˜μ•Όν•œλ‹€. κ·Έλ ‡κ²Œ 되면 였λ₯˜ λ°œμƒ μ‹œ buyFavoriteSnack ν•¨μˆ˜μ—μ„œ 였λ₯˜κ°€ μ „νŒŒλœλ‹€.

struct PurchasedSnack {
    let name: String
    init(name: String, vendingMachine: VendingMachine) throws {
        try vendingMachine.vend(itemNamed: name)
        self.name = name
    }
}

Throwing μƒμ„±μžλŠ” ν•¨μˆ˜μ—μ„œ 였λ₯˜λ₯Ό λ°œμƒν•˜λŠ” 것과 같은 λ°©μ‹μœΌλ‘œ 였λ₯˜λ₯Ό μ „νŒŒν•  수 μžˆλ‹€. 예λ₯Όλ“€μ–΄ μœ„μ˜ μ½”λ“œμ—μ„œ PurchaseSnack ꡬ쑰체의 μƒμ„±μžλŠ” μ΄ˆκΈ°ν™” ν”„λ‘œμ„ΈμŠ€μ˜ μΌλΆ€λ‘œ throwing ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜κ²Œ λ˜λŠ”λ° λ§Œμ•½ 였λ₯˜κ°€ λ°œμƒν•œλ‹€λ©΄ ν•΄λ‹Ή 였λ₯˜λ₯Ό ν˜ΈμΆœμžμ—κ²Œ μ „νŒŒν•˜μ—¬ μ²˜λ¦¬ν•  수 있게 ν•œλ‹€.

 

2. Do-catch ꡬ문을 μ΄μš©ν•΄μ„œ μ—λŸ¬λ₯Ό μ²˜λ¦¬ν•˜κΈ°

do-catch λ₯Ό μ΄μš©ν•˜μ—¬ μ—λŸ¬λ₯Ό μ²˜λ¦¬ν•  수 μžˆλ‹€. λ§Œμ•½ μ—λŸ¬κ°€ do ꡬ문 μ•ˆμ—μ„œ λ°œμƒν•œλ‹€λ©΄, λ°œμƒν•˜λŠ” μ—λŸ¬μ˜ μ’…λ₯˜λ₯Ό catch ꡬ문으둜 κ΅¬λΆ„ν•˜μ—¬ μ²˜λ¦¬ν•˜λŠ” 것이닀.

do {
    try expression
    statements
} catch pattern 1 {
    statements
} catch pattern 2 where condition {
    statements
} catch {
    statements
}

catch ꡬ문 뒀에 μ–΄λ–€ μ—λŸ¬μΈμ§€ 적고 그것을 μ–΄λ–»κ²Œ μ²˜λ¦¬ν•  것인지 λͺ…μ‹œν•  수 μžˆλ‹€. λ§Œμ•½ catch ꡬ문뒀에 μ—λŸ¬ μ’…λ₯˜λ₯Ό λͺ…μ‹œν•˜μ§€ μ•ŠμœΌλ©΄ λ°œμƒν•˜λŠ” λͺ¨λ“  μ—λŸ¬λ₯Ό μ§€μ—­μƒμˆ˜μΈ error 둜 λ°”μΈλ”©ν•œλ‹€.

 

λ‹€μŒ μ½”λ“œλŠ” VendingMachineError μ—΄κ±°ν˜•μ˜ λͺ¨λ“  세가지 μ—λŸ¬ μ’…λ₯˜μ— λŒ€ν•΄ μ²˜λ¦¬ν•˜λŠ” μ½”λ“œμ΄λ‹€.

var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8
do {
    try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
    print("Success! Yum.")
} catch VendingMachineError.invalidSelection {
    print("Invalid Selection.")
} catch VendingMachineError.outOfStock {
    print("Out of Stock.")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {
    print("Insufficient funds. Please insert an additional \\(coinsNeeded) coins.")
} catch {
    print("Unexpected error: \\(error).")
}
// Prints "Insufficient funds. Please insert an additional 2 coins."

μœ„ μ˜ˆμ œμ—μ„œ buyFavoriteSnack(person: vendingMachine: ) ν•¨μˆ˜λŠ” try ν‘œν˜„μ•ˆμ—μ„œ ν˜ΈμΆœλœλ‹€. μ™œλƒν•˜λ©΄ 이 ν•¨μˆ˜κ°€ μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚¬ 수 있기 λ•Œλ¬Έμ— μ—λŸ¬κ°€ λ°œμƒν•˜μžλ§ˆμž catch ꡬ문에 전달해 μ μ ˆν•œ 처리λ₯Ό ν•  수 있게 ν•˜κΈ° μœ„ν•΄μ„œλ‹€. λ§Œμ•½ λ°œμƒν•œ μ—λŸ¬ μ’…λ₯˜λ₯Ό μ²˜λ¦¬ν•˜λŠ” catchꡬ문이 μ—†λ‹€λ©΄, μ—λŸ¬λŠ” λ§ˆμ§€λ§‰ catch ꡬ문에 걸리게 λ˜μ–΄ 지역 μƒμˆ˜ error 둜 μ²˜λ¦¬ν•  수 μžˆλ‹€.

μœ„μ˜ μ½”λ“œμ—μ„œ μ‚¬μš©λœ buyFavoriteSnack ν•¨μˆ˜λŠ” μ•„κΉŒ μ •μ˜ν•  λ•Œ 였λ₯˜λ₯Ό λ°œμƒν•  수 μžˆλŠ” ν•¨μˆ˜λ‘œ μ •μ˜ν–ˆκΈ° λ•Œλ¬Έμ— try와 ν•¨κ»˜ μ‚¬μš©λ˜μ–΄μ•Ό ν•œλ‹€. λ§Œμ•½ 였λ₯˜κ°€ λ°œμƒν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ κ·Έλƒ₯ μ‹€ν–‰λ˜μ§€λ§Œ 였λ₯˜κ°€ λ°œμƒν•˜κ²Œ 되면 μ–΄λ–€ 였λ₯˜κ°€ λ°œμƒν–ˆλŠ”μ§€μ— 따라 catch 절이 μ„ νƒλœλ‹€. catch μ ˆμ—μ„œ do μ ˆμ—μ„œ λ°œμƒ κ°€λŠ₯ν•œ λͺ¨λ“  였λ₯˜λ₯Ό μ²˜λ¦¬ν•  ν•„μš”λŠ” μ—†κ³  μ „νŒŒλ§Œ 해도 λœλ‹€. ν•˜μ§€λ§Œ κ²°κ΅­ μ „νŒŒλœ 였λ₯˜λŠ” 또 μ–Έμ  κ°€λŠ” μ²˜λ¦¬λ˜μ–΄μ•Ό ν•œλ‹€. λ§Œμ•½ 였λ₯˜κ°€ μ²˜λ¦¬λ˜μ§€ μ•Šκ³  μ΅œμƒμœ„ λ²”μœ„λ‘œ μ „νŒŒλ˜λŠ” κ²½μš°μ—” λŸ°νƒ€μž„ 였λ₯˜κ°€ λ°œμƒν•˜κ²Œ λœλ‹€.

func nourish(with item: String) throws {
    do {
        try vendingMachine.vend(itemNamed: item)
    } catch is VendingMachineError {    // λͺ¨λ“  VendingMachineError ꡬ뢄을 μœ„ν•΄ isλ₯Ό μ‚¬μš©
        print("Invalid selection, out of stock, or not enough money.")
    }
}

do {
    try nourish(with: "Beet-Flavored Chips")
} catch {
    print("Unexpected non-vending-machine-related error: \\(error)")
      // μ—¬κΈ°μ—μ„œ 처럼 catchλ₯Ό κ·Έλƒ₯ if-elseμ—μ„œ else 같이 μ‚¬μš© κ°€λŠ₯
}
// Prints "Invalid selection, out of stock, or not enough money."

μœ„ μ½”λ“œμ—μ„œλŠ” ν•¨μˆ˜ λ‚΄μ—μ„œ VendinMachineError λ₯Ό μ²˜λ¦¬ν•  수 μžˆλ„λ‘ μ •μ˜λ˜μ—‰γ…†λ‹€. ν•˜μ§€λ§Œ κ·Έ μ™Έμ˜ μ—λŸ¬λŠ” μ²˜λ¦¬ν•˜μ§€ μ•Šκ³  κ·Έλƒ₯ μ „νŒŒλ§Œ ν•œλ‹€. κ·Έλ ‡κΈ° λ•Œλ¬Έμ— μ‹€μ œλ‘œ μ‚¬μš©ν•  λ•ŒλŠ” do-catch 문을 ν•˜λ‚˜ 더 μ‚¬μš©ν•˜μ—¬ κ·Έ λ°–μ˜ μ—λŸ¬μ— λŒ€ν•œ 처리λ₯Ό μˆ˜ν–‰ν•΄μ£ΌλŠ” μ½”λ“œμ΄λ‹€.

func eat(item: String) throws {
    do {
        try vendingMachine.vend(itemNamed: item)
    } catch VendingMachineError.invalidSelection, VendingMachineError.insufficientFunds, VendingMachineError.outOfStock {
        print("Invalid selection, out of stock, or not enough money.")
    }
}

μ—¬λŸ¬ 개의 였λ₯˜λ₯Ό λ™μΌν•˜κ²Œ μ²˜λ¦¬ν•˜λŠ” 방법은 catch 뒀에 였λ₯˜μ˜ μ’…λ₯˜λ₯Ό λ‚˜νƒ€λ‚Ό λ•Œ μ‰Όν‘œ , 둜 κ΅¬λΆ„ν•˜λŠ” 것이닀. μœ„ μ½”λ“œμ²˜λŸΌ λ§Œλ“€λ©΄ μ„Έ 가지 였λ₯˜μ— λŒ€ν•΄μ„œ λͺ¨λ‘ λ™μΌν•œ 처리λ₯Ό ν•œλ‹€.

 

3. μ—λŸ¬λ₯Ό μ˜΅μ…”λ„ κ°’μœΌλ‘œ λ°˜ν™˜ν•˜κΈ°

try? ꡬ문을 μ‚¬μš©ν•΄μ„œ μ—λŸ¬λ₯Ό μ˜΅μ…”λ„ κ°’μœΌλ‘œ λ°˜ν™˜ν•  수 μžˆλ‹€. λ§Œμ•½ μ—λŸ¬κ°€ try? λ‚΄μ—μ„œ λ°œμƒν•œλ‹€λ©΄ κ·Έ 값은 nil 이 λœλ‹€.

func someThrowingFunction() throws -> Int {
    // ...
}

let x = try? someThrowingFunction()

let y: Int?
do {
    y = try someThrowingFunction()
} catch {
    y = nil
}

λ§Œμ•½ someThrowingFunction이 μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚€λ©΄ x와 yλŠ” nil μ΄λœλ‹€. 그렇지 μ•ŠμœΌλ©΄ 리턴값을 κ°–λŠ”λ‹€. x와 yλŠ” someThrowingFunction의 νƒ€μž…μ΄ μ–΄λ–»λ“  상관없이 μ˜΅μ…”λ„ 값을 κ°–κ²Œ λœλ‹€.

try?λŠ” λ§Œμ•½ λ°œμƒν•˜λŠ” λͺ¨λ“  μ—λŸ¬λ₯Ό 같은 λ°©μ‹μœΌλ‘œ μ²˜λ¦¬ν•˜κ³  싢을 λ•Œ μ‚¬μš©λœλ‹€. λ‹€μŒ μ½”λ“œμ—μ„œλŠ” 데이터λ₯Ό κ°€μ Έμ˜€λŠ” μ—¬λŸ¬ μ ‘κ·Ό 방법을 μ‹œλ„ν•˜λŠ”λ° 접근방법이 λͺ¨λ‘ μ‹€νŒ¨ν•˜λ©΄ nil 을 λ°˜ν™˜ν•œλ‹€.

func fetchData() -> Data? {
    if let data = try? fetchDataFromDisk() { return data }
    if let data = try? fetchDataFromServer() { return data }
    return nil
}

 

 

4. μ—λŸ¬ λ°œμƒμ„ μ€‘μ§€μ‹œν‚€κΈ° (assert)

λ§Œμ•½ throwing ν•¨μˆ˜λ‚˜ λ©”μ„œλ“œκ°€ λŸ°νƒ€μž„ μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚€μ§€ μ•Šμ„ κ²ƒμ΄λΌλŠ” 확신이 λ“œλŠ” 경우 try!λ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€. ν•˜μ§€λ§Œ 이 경우 였λ₯˜κ°€ λ°œμƒν•˜λ©΄ λŸ°νƒ€μž„ μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚€λ‹ˆ μ£Όμ˜ν•˜μž.

let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")

μœ„ μ½”λ“œλŠ” μ§€μ •λœ 경둜의 이미지 λ¦¬μ†ŒμŠ€λ₯Ό λ‘œλ“œν•˜λŠ” μ½”λ“œμ΄κ³  μ—¬κΈ°μ„œ μ‚¬μš©λœ loadImage ν•¨μˆ˜λŠ” 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚¬ 수 μžˆλŠ” ν•¨μˆ˜μ΄λ‹€. ν•˜μ§€λ§Œ κ°œλ°œμžκ°€ μ ˆλŒ€λ‘œ λ°œμƒν•˜μ§€ μ•Šμ„ 것이라고 ν™•μ‹ ν•˜λ©΄ μœ„μ²˜λŸΌ try! λ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€.


 

Specifying Cleanup Action

μ½”λ“œ 싀행이 ν˜„μž¬ μ½”λ“œ 블둝을 λ– λ‚˜κΈ° 직전에 defer 문을 μ‚¬μš©ν•˜μ—¬ νŠΉμ • μ½”λ“œλ₯Ό μ‹€ν–‰ν•  수 μžˆλ‹€. 이 λͺ…령문을 μ‹€ν–‰ν•˜λ©΄ ν˜„μž¬ μ½”λ“œ 블둝을 λ– λ‚˜λŠ” 방식에 관계없이 μˆ˜ν–‰ν•΄μ•Ό ν•˜λŠ” μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆλ‹€. 예λ₯Ό λ“€μ–΄ 였λ₯˜κ°€ λ°œμƒν•˜μ—¬ μ’…λ£Œν•˜κ±°λ‚˜ return, break와 같은 λͺ…령문에 μ˜ν•΄ μ’…λ£Œλ˜λŠ” 경우 defer 문을 μ‚¬μš©ν•˜μ—¬ 파일 λ””μŠ€ν¬λ¦½ν„°κ°€ λ‹«νžˆκ³  λ©”λͺ¨λ¦¬ 할당을 μˆ˜λ™μœΌλ‘œ ν•΄μ œν•  수 μžˆλ‹€.

defer문은 ν˜„μž¬ λ²”μœ„κ°€ μ’…λ£Œλ  λ•ŒκΉŒμ§€ 싀행을 μ—°κΈ°ν•œλ‹€. 이 ꡬ문은 defer ν‚€μ›Œλ“œμ™€ λ‚˜μ€‘μ— 싀행될 μ½”λ“œλ‘œ κ΅¬μ„±λœλ‹€. λ‚˜μ€‘μ— 싀행될 μ½”λ“œμ—λŠ” break, returnκ³Ό 같은 μ œμ–΄λ₯Ό μ „μ†‘ν•˜κ±°λ‚˜ 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚€λŠ” μ½”λ“œλ₯Ό μž‘μ„±ν•  수 μ—†λ‹€. μ§€μ—°λœ μž‘μ—…μ€ μ†ŒμŠ€ μ½”λ“œμ—μ„œ μž‘μ„±λœ μˆœμ„œμ™€λŠ” λ°˜λŒ€λ‘œ μ‹€ν–‰λœλ‹€. 즉 첫 번째 defer 문의 μ½”λ“œκ°€ λ§ˆμ§€λ§‰μœΌλ‘œ μ‹€ν–‰λ˜κ³  두 번째 defer문의 μ½”λ“œκ°€ 그전에 μ‹€ν–‰λœλ‹€. 즉 λ§ˆμ§€λ§‰μ— κ΅¬ν˜„λœ defer문이 제일 λ¨Όμ € μ‹€ν–‰λœλ‹€.

func processFile(filename: String) throws {
    if exists(filename) {
        let file = open(filename)
        defer {
            close(file) // block이 λλ‚˜κΈ° 직전에 μ‹€ν–‰, 주둜 μžμ› ν•΄μ œλ‚˜ 정지에 μ‚¬μš©
        }
        while let line = try file.readline() {
            // Work with the file.
        }
        // close(file) is called here, at the end of the scope.
    }
}

μœ„ μ˜ˆμ œλŠ” defer ꡬ문을 μ΄μš©ν•΄ open(:) ν•¨μˆ˜μ™€ 짝을 μ΄λ£¨λŠ” close(:) ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•œλ‹€. 

λ°˜μ‘ν˜•