๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿฅ– Bread Basics/Swift

Swift ๊ณต์‹ ๋ฌธ์„œ ์ •๋ฆฌ - ์—๋Ÿฌ ์ฒ˜๋ฆฌ (Error Handling)

by BreadDev 2025. 4. 11.
728x90

์•ˆ๋…•ํ•˜์„ธ์š”. ์˜ค๋Š˜์€ Swift '์—๋Ÿฌ ์ฒ˜๋ฆฌ(Error Handling)'์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ์•ฑ ๊ฐœ๋ฐœ ์‹œ ๋ฐœ์ƒํ•˜๋Š” ๋‹ค์–‘ํ•œ ์˜ˆ์™ธ ์ƒํ™ฉ์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š”์ง€, Swift์˜ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ํ†ตํ•ด ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๐Ÿ“Œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋ž€? (Introduction to Error Handling)

์—๋Ÿฌ ์ฒ˜๋ฆฌ๋Š” ํ”„๋กœ๊ทธ๋žจ์ด ์‹คํ–‰ ์ค‘์— ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์ƒํ™ฉ์— ๋Œ€์‘ํ•˜๊ณ  ๋ณต๊ตฌํ•˜๋Š” ํ”„๋กœ์„ธ์Šค์ž…๋‹ˆ๋‹ค. Swift๋Š” ๋Ÿฐํƒ€์ž„์— ๋ฐœ์ƒ ๊ฐ€๋Šฅํ•œ ์—๋Ÿฌ๋ฅผ ๋˜์ง€๊ณ (throw), ํฌ์ฐฉํ•˜๊ณ (catch), ์ „ํŒŒ(propagate)ํ•˜๋Š” ๊ฐ•๋ ฅํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์˜ต์…”๋„์ด ๊ฐ’์˜ ๋ถ€์žฌ๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋ผ๋ฉด, ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋Š” '์™œ' ์ž‘์—…์ด ์‹คํŒจํ–ˆ๋Š”์ง€์— ๋Œ€ํ•œ ์ •๋ณด๊นŒ์ง€ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ฝ”๋“œ๋Š” ์ƒํ™ฉ์— ๋งž๊ฒŒ ๋” ์ ์ ˆํ•˜๊ฒŒ ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹ค์ œ ์‚ฌ๋ก€: ํŒŒ์ผ์„ ์ฝ๋Š” ์ž‘์—…์—์„œ 'ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์Œ', '๊ถŒํ•œ ๋ถ€์กฑ', 'ํฌ๋งท ๋ถˆ์ผ์น˜' ๋“ฑ ๋‹ค์–‘ํ•œ ์ด์œ ๋กœ ์‹คํŒจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋ฅผ ํ†ตํ•ด ์ด๋Ÿฌํ•œ ์ƒํ™ฉ์„ ๊ตฌ๋ถ„ํ•˜์—ฌ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“Œ ์—๋Ÿฌ ํ‘œํ˜„๊ณผ ๋˜์ง€๊ธฐ (Representing and Throwing Errors)

์—๋Ÿฌ ์ •์˜ํ•˜๊ธฐ

Swift์—์„œ ์—๋Ÿฌ๋Š” Error ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š” ํƒ€์ž…์œผ๋กœ ํ‘œํ˜„๋ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์—ด๊ฑฐํ˜•(enum)์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ด€๋ จ๋œ ์—๋Ÿฌ ์กฐ๊ฑด๋“ค์„ ๊ทธ๋ฃนํ™”ํ•ฉ๋‹ˆ๋‹ค:

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

ํฌ์ธํŠธ: ์—ด๊ฑฐํ˜•์€ ์—๋Ÿฌ ์กฐ๊ฑด์„ ๋ชจ๋ธ๋งํ•˜๋Š”๋ฐ ์ด์ƒ์ ์ด๋ฉฐ, ๊ด€๋ จ ๊ฐ’(associated values)์„ ํ†ตํ•ด ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—๋Ÿฌ ๋˜์ง€๊ธฐ

์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ๋Š” throw ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—๋Ÿฌ๋ฅผ '๋˜์ง‘๋‹ˆ๋‹ค':

throw VendingMachineError.insufficientFunds(coinsNeeded: 5)

์ด ์ฝ”๋“œ๋Š” "์žํŒ๊ธฐ์— 5์ฝ”์ธ์ด ๋” ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค"๋ผ๋Š” ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

๐Ÿ“Œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ• (Handling Errors)

Swift์—์„œ๋Š” ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” 4๊ฐ€์ง€ ์ฃผ์š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค:

1. ์—๋Ÿฌ ์ „ํŒŒํ•˜๊ธฐ (Propagating Errors)

ํ•จ์ˆ˜๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค๋ฉด, ํ•จ์ˆ˜ ์„ ์–ธ์— throws ํ‚ค์›Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ด๋ฅผ ํ˜ธ์ถœ์ž์—๊ฒŒ ์•Œ๋ฆฝ๋‹ˆ๋‹ค:

func canThrowErrors() throws -> String

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)
    }
    
    // ํŒ๋งค ๊ณผ์ • ์ˆ˜ํ–‰...
}

throws ํ•จ์ˆ˜: ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋Š” throws ํ‚ค์›Œ๋“œ๋กœ ํ‘œ์‹œํ•˜๋ฉฐ, ์ด๋Ÿฌํ•œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋Š” try ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์—๋Ÿฌ๋ฅผ ๋˜์งˆ ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ try ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค:

func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
    let snackName = favoriteSnacks[person] ?? "Candy Bar"
    try vendingMachine.vend(itemNamed: snackName)
}

2. do-catch๋กœ ์—๋Ÿฌ ์ฒ˜๋ฆฌํ•˜๊ธฐ

do-catch ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋ฉด ์—๋Ÿฌ๋ฅผ ํฌ์ฐฉํ•˜๊ณ  ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

do {
    try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
    print("๊ตฌ๋งค ์„ฑ๊ณต! ๋ง›์žˆ๊ฒŒ ๋“œ์„ธ์š”.")
} catch VendingMachineError.invalidSelection {
    print("์ž˜๋ชป๋œ ์„ ํƒ์ž…๋‹ˆ๋‹ค.")
} catch VendingMachineError.outOfStock {
    print("ํ’ˆ์ ˆ์ž…๋‹ˆ๋‹ค.")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {
    print("์ž”์•ก์ด ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค. \(coinsNeeded)์ฝ”์ธ์„ ๋” ๋„ฃ์–ด์ฃผ์„ธ์š”.")
} catch {
    print("์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์—๋Ÿฌ: \(error).")
}

์บ์น˜ ํŒจํ„ด: catch ๋’ค์— ํŠน์ • ์—๋Ÿฌ ํŒจํ„ด์„ ์ง€์ •ํ•˜๊ฑฐ๋‚˜, ํŒจํ„ด ์—†์ด ๋ชจ๋“  ์—๋Ÿฌ๋ฅผ ํฌ์ฐฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ ์—๋Ÿฌ๋ฅผ ํ•œ๊บผ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ฝค๋งˆ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค:

catch VendingMachineError.invalidSelection, VendingMachineError.insufficientFunds, VendingMachineError.outOfStock {
    print("์„ ํƒ์ด ์ž˜๋ชป๋˜์—ˆ๊ฑฐ๋‚˜, ํ’ˆ์ ˆ์ด๊ฑฐ๋‚˜, ์ž”์•ก์ด ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค.")
}

3. ์˜ต์…”๋„ ๊ฐ’์œผ๋กœ ์—๋Ÿฌ ๋ณ€ํ™˜ํ•˜๊ธฐ

try?๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—๋Ÿฌ๋ฅผ ์˜ต์…”๋„ ๊ฐ’์œผ๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ์—๋Ÿฌ๋ฅผ ๋˜์ง€๋ฉด ๊ฒฐ๊ณผ๋Š” nil์ด ๋ฉ๋‹ˆ๋‹ค:

// ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ x๋Š” nil์ด ๋ฉ๋‹ˆ๋‹ค
let x = try? someThrowingFunction()

// ์œ„ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค
let y: Int?
do {
    y = try someThrowingFunction()
} catch {
    y = nil
}

์‹ค์šฉ์  ์‚ฌ์šฉ๋ฒ•: try?๋Š” ์—ฌ๋Ÿฌ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‹œ๋„ํ•˜๋ฉด์„œ ์ฒซ ๋ฒˆ์งธ ์„ฑ๊ณตํ•œ ๊ฒฐ๊ณผ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค:

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

4. ์—๋Ÿฌ ์ „ํŒŒ ๋น„ํ™œ์„ฑํ™”ํ•˜๊ธฐ

ํ•จ์ˆ˜๊ฐ€ ์‹ค์ œ๋กœ ์—๋Ÿฌ๋ฅผ ๋˜์ง€์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๊ณ  ํ™•์‹ ํ•œ๋‹ค๋ฉด try!๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—๋Ÿฌ ์ „ํŒŒ๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

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

์ฃผ์˜: try!๋Š” ๋งŒ์•ฝ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋Ÿฐํƒ€์ž„ ํฌ๋ž˜์‹œ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ์ ˆ๋Œ€์ ์œผ๋กœ ํ™•์‹ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•˜์„ธ์š”.

๐Ÿ“Œ ์—๋Ÿฌ ํƒ€์ž… ์ง€์ • (Specifying Error Types)

Swift 5.7๋ถ€ํ„ฐ๋Š” ํ•จ์ˆ˜๊ฐ€ ๋˜์งˆ ์ˆ˜ ์žˆ๋Š” ์—๋Ÿฌ์˜ ํƒ€์ž…์„ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

enum StatisticsError: Error {
    case noRatings
    case invalidRating(Int)
}

func summarize(_ ratings: [Int]) throws(StatisticsError) {
    guard !ratings.isEmpty else { throw .noRatings }

    var counts = [1: 0, 2: 0, 3: 0]
    for rating in ratings {
        guard rating > 0 && rating <= 3 else { throw .invalidRating(rating) }
        counts[rating]! += 1
    }

    print("*", counts[1]!, "-- **", counts[2]!, "-- ***", counts[3]!)
}

ํƒ€์ž…์ด ์ง€์ •๋œ ๋˜์ง€๊ธฐ(Typed Throws): ํ•จ์ˆ˜๊ฐ€ ๋˜์งˆ ์ˆ˜ ์žˆ๋Š” ์—๋Ÿฌ ํƒ€์ž…์„ throws(ํƒ€์ž…์ด๋ฆ„)์œผ๋กœ ๋ช…์‹œํ•˜๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํƒ€์ž… ์ฒดํฌ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํƒ€์ž…์ด ์ง€์ •๋œ ์—๋Ÿฌ๋ฅผ ํฌ์ฐฉํ•  ๋•Œ๋Š” ํ•ด๋‹น ์—๋Ÿฌ ํƒ€์ž…์— ๋งž๋Š” ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค:

do throws(StatisticsError) {
    try summarize(ratings)
} catch {
    switch error {
    case .noRatings:
        print("ํ‰์  ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค")
    case .invalidRating(let rating):
        print("์œ ํšจํ•˜์ง€ ์•Š์€ ํ‰์ : \(rating)")
    }
}

์ด์ : ์—๋Ÿฌ ํƒ€์ž…์„ ๋ช…์‹œํ•˜๋ฉด ์ฝ”๋“œ์˜ ์•ˆ์ „์„ฑ์ด ๋†’์•„์ง€๊ณ , ๋ชจ๋“  ์—๋Ÿฌ ์ผ€์ด์Šค๋ฅผ ์ฒ˜๋ฆฌํ–ˆ๋Š”์ง€ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“Œ ์ •๋ฆฌ ์ž‘์—… ์ง€์ • (Cleanup Actions with defer)

defer ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋ฉด ํ˜„์žฌ ์ฝ”๋“œ ๋ธ”๋ก์ด ์ข…๋ฃŒ๋  ๋•Œ ์‹คํ–‰๋  ์ฝ”๋“œ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํ•จ์ˆ˜๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ข…๋ฃŒ๋˜๋“ , ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋“  ์ƒ๊ด€์—†์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค:

func processFile(filename: String) throws {
    if exists(filename) {
        let file = open(filename)
        defer {
            close(file)  // ํ•จ์ˆ˜ ์ข…๋ฃŒ ์‹œ ํ•ญ์ƒ ํŒŒ์ผ์„ ๋‹ซ์Šต๋‹ˆ๋‹ค
        }
        
        while let line = try file.readline() {
            // ํŒŒ์ผ ์ฒ˜๋ฆฌ ์ฝ”๋“œ...
        }
    }
}

defer์˜ ์‹คํ–‰ ์ˆœ์„œ: ์—ฌ๋Ÿฌ defer ๋ธ”๋ก์ด ์žˆ๋‹ค๋ฉด ๋งˆ์ง€๋ง‰์— ์ •์˜๋œ ๊ฒƒ๋ถ€ํ„ฐ ์—ญ์ˆœ์œผ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

defer๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค:

  • ํŒŒ์ผ ํ•ธ๋“ค, ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ ๋“ฑ์˜ ๋ฆฌ์†Œ์Šค ํ•ด์ œ
  • ์ž ๊ธˆ(lock) ํ•ด์ œ
  • ์ž„์‹œ ์ƒํƒœ ๋ณต์›

๐Ÿ“Œ ์‹ค์ œ ์˜ˆ์ œ: ์žํŒ๊ธฐ ์‹œ๋ฎฌ๋ ˆ์ด์…˜

๋‹ค์Œ์€ ์ง€๊ธˆ๊นŒ์ง€ ๋ฐฐ์šด ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ธฐ๋ฒ•์„ ์ข…ํ•ฉ์ ์œผ๋กœ ํ™œ์šฉํ•œ ์žํŒ๊ธฐ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค:

// ์ƒํ’ˆ ๊ตฌ์กฐ์ฒด
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("\(name) ์ƒํ’ˆ์ด ๋‚˜์™”์Šต๋‹ˆ๋‹ค")
    }
}

// ์‚ฌ์šฉ ์˜ˆ์‹œ
let favoriteSnacks = [
    "Alice": "Chips",
    "Bob": "Licorice",
    "Eve": "Pretzels",
]

var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8

do {
    try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
    print("๊ตฌ๋งค ์„ฑ๊ณต!")
} catch VendingMachineError.invalidSelection {
    print("์„ ํƒํ•œ ์ƒํ’ˆ์ด ์—†์Šต๋‹ˆ๋‹ค.")
} catch VendingMachineError.outOfStock {
    print("ํ’ˆ์ ˆ์ž…๋‹ˆ๋‹ค.")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {
    print("์ž”์•ก์ด ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค. \(coinsNeeded)์ฝ”์ธ์„ ๋” ๋„ฃ์–ด์ฃผ์„ธ์š”.")
} catch {
    print("์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์—๋Ÿฌ: \(error)")
}

๐Ÿ“Œ ์ •๋ฆฌ: Swift์˜ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์ฒ ํ•™

Swift์˜ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์‹œ์Šคํ…œ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฒ ํ•™์„ ๋ฐ”ํƒ•์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค:

  1. ๋ช…์‹œ์„ฑ: ์—๋Ÿฌ๋ฅผ ๋˜์งˆ ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋Š” throws๋กœ ๋ช…ํ™•ํžˆ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
  2. ํƒ€์ž… ์•ˆ์ „์„ฑ: ์—๋Ÿฌ๋„ ํƒ€์ž… ์‹œ์Šคํ…œ์˜ ์ผ๋ถ€๋กœ, ์ปดํŒŒ์ผ ํƒ€์ž„์— ๋งŽ์€ ๋ฌธ์ œ๋ฅผ ์žก์•„๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ๋น„์šฉ ํšจ์œจ์„ฑ: Swift์˜ ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋Š” ์˜ˆ์™ธ ์ฒ˜๋ฆฌ์™€ ๋‹ฌ๋ฆฌ ์Šคํƒ ๋˜๊ฐ๊ธฐ(stack unwinding)๊ฐ€ ์—†์–ด ์„ฑ๋Šฅ์ƒ ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  4. ํ†ตํ•ฉ์„ฑ: ์˜ต์…”๋„, ํƒ€์ž… ์‹œ์Šคํ…œ ๋“ฑ Swift์˜ ๋‹ค๋ฅธ ๊ธฐ๋Šฅ๊ณผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ†ตํ•ฉ๋ฉ๋‹ˆ๋‹ค.

์—๋Ÿฌ ์ฒ˜๋ฆฌ๋ฅผ ์ž˜ ํ™œ์šฉํ•˜๋ฉด ๋” ์•ˆ์ •์ ์ด๊ณ  ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์‰ฌ์šด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์ƒํ™ฉ์—์„œ๋„ ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.