티스토리 뷰

1. 오류처리란

  • 오류처리는 프로그램이 오류를 일으켰을 때, 감지하고 회복하는 일련의 과정

2. 오류의 표현

  • 스위프트에서 오류는 Error라는 프로토콜을 준수하는 타입의 값을 통해 표현
  • Error는 요구사항 없는 빈 프로토콜
  • 오류를 표현하기 위한 타입은 이 프로토콜을 채택함(주로 열거형)
//스마트폰에서 발생할 수 있는 에러
enum phoneError: Error {
    case notConnectedToInternet
    case notSupportedOnDevice
    case outOfMemory
}
  • 위 코드에서 Error 프로토콜을 채택한 것을 통해 오류처리를 위한 열거형임을 알 수 있음
  • 오류의 종류를 예상하고, 오류 때문에 다음에 행할 동작이 정상적으로 진행되지 않으면 오류를 던져줌
  • 오류를 던져줄 때는 throw 구문 사용

3.오류 포착 및 처리

  • 오류를 던질 수 있지만, 그 오류를 처리하기 위한 코드가 필요함
  • 오류를 처리하기 위한 네가지 방법
    • 함수에서 발생한 오류를 해당 함수를 호출한 코드에 알리기
    • do-catch 사용
    • 옵셔널 값으로 오류 처리
    • 오류가 발생하지 않을 것이라고 확신
  1. 함수에서 발생한 오류 알리기
    1. 함수에서 발생한 오류를 해당 함수를 호출한 코드에 알리는 방법
    2. try 키워드로 던져진 오류를 받을 수 있음(try, try!, try? 등)
    3. 함수, 메서드, 이니셜라이저의 매개변수 뒤에 throws 키워드로 오류를 던질 수 있음
      1. func cannotThrowErrors() → String // 기본
      2. func cannotThrowErrors() throws → String // 오류 던지기
    4. 아래의 예제
      1. 오류가 발생했을 때 제어를 위해 gaurd를 사용
      2. 조건이 충족되지 않으면 throw를 통해 오류를 알림
      3. 오류를 던질 수 있는 함수, 메서드, 이니셜라이저를 호출하는 코드는 반드시 오류를 처리할 수 있는 구문을 작성해주어야 함
      4. 그러나 아래 코드는 알려주기만 할 뿐 처리할 수 있는 코드가 없음
enum VendingMachineError: Error {
    case invalidSelection
    case insufficientFunds(coinsNeed: Int)
    case outOfStock
}

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),
        "Biscuit": Item(price: 7, count: 11)
    ]

    var coinsDeposited = 0

    func dispense(snack: String) {
        print("\(snack) 제공")
    }

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

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

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

        self.coinsDeposited -= item.price

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

        self.dispense(snack: name)
    }
}

let favoriteSnacks = [
    "soul": "Chips",
    "model": "Biscuit",
    "bom": "Chocolate"
]

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

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

let machine: VendingMachine = VendingMachine()
machine.coinsDeposited = 30

var purchase: PurchasedSnack = try PurchasedSnack(name: "Biscuit", vendingMachine: machine) // Biscuit 제공

 print(purchase.name) // Biscuit

print("---")
for (person, favoriteSnack) in favoriteSnacks {
    print(person, favoriteSnack)
    try buyFavoriteSnack(person: person, vendingMachine: machine)
}

//model Biscuit
//Biscuit 제공
//soul Chips
//Chips 제공
//bom Chocolate
//Playground execution terminated: An error was thrown and was not caught:
//__lldb_expr_139.VendingMachineError.invalidSelection << 오류 발생
  1. do-catch 구문을 이용해서 오류처리
    1. 기본적인 do-catch 구문
    2. 위의 코드를 do-catch 을 처리, 오류를 다시 던지지 않아도 되게 되었음
//a. 기본적인 do-catch 구문
do {
    try <#오류 발생 코드#>
    <#오류가 발생하지 않으면 실행할 코드#>
} catch <#오류 패턴1#> {
    <#처리 코드#>
} catch <#오류 패턴#> where <#추가 조건#> {
    <#처리 코드#>
}
import Foundation

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

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),
        "Biscuit": Item(price: 7, count: 11)
    ]

    var coinsDeposited = 0

    func dispense(snack: String) {
        print("\(snack) 제공")
    }

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

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

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

        self.coinsDeposited -= item.price

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

        self.dispense(snack: name)
    }
}

let favoriteSnacks = [
    "soul": "Chips",
    "model": "Biscuit",
    "bom": "Chocolate"
]

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

}

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

func tringVend(itemNamed name: String, vendingMachine: VendingMachine) {
    do {
        try vendingMachine.vend(itemNamed: name)
    } catch VendingMachineError.invalidSelection {
        print("ERROR: \(name) is not vaild")
    } catch VendingMachineError.outOfStock {
        print("ERROR: Out of Stock")
    } catch VendingMachineError.insufficientFunds(let coinsNeeded) {
        print("ERROR: Coins is not enough. Please insert \(coinsNeeded)coin more.")
    } catch {
        print("OTHER ERROR")
    }
}

let machine: VendingMachine = VendingMachine()
machine.coinsDeposited = 20

//var purchase: PurchasedSnack = try PurchasedSnack(name: "Biscuit", vendingMachine: machine) // Biscuit 제공
var purchase: PurchasedSnack = PurchasedSnack(name: "Biscuit", vendingMachine: machine) // Biscuit 제공
print(purchase.name) // Biscuit

purchase = PurchasedSnack(name: "Ice Cream", vendingMachine: machine)
print(purchase.name) // IceCream

print("---")
for (person, favoriteSnack) in favoriteSnacks {
    print(person, favoriteSnack)
    try buyFavoriteSnack(person: person, vendingMachine: machine)
}

//bom Chocolate
//ERROR: Chocolate is not vaild
//soul Chips
//Chips 제공
//model Biscuit
//ERROR: Coins is not enough. Please insert 4coin more.
댓글