Swift - Error Handling

이한솔·2023년 9월 25일
0

Swift 문법 🍎

목록 보기
27/32

⚒️ Error Handling

Error Handling은 프로그램에서 에러 조건들에 대해 대응하고 회복하는 프로세스이다. Swift는 런타임에서 에러가 발생한 경우 해당 에러를 처리하기 위해 throwing, catching, propagting, manipulating을 지원하는 일급 클래스(first-class)를 제공한다.

Swift의 에러 핸들링은 Cocoa와 Objective-C의 NSError 클래스와 상호호환되는 에러 핸들링 패턴을 사용한다.

오류 표현

Error Protocol과 주로 enum을 통해서 오류를 표현한다.

enum 오류종류이름: Error {
    case 종류1
    case 종류2
    case 종류3
    //...
}

enum CoffeeMachineError: Error {
    case invalidInput
    case insufficienCoffes
    case insufficientFunds(requiredCoins: Int)
}

오류 던지기

오류 발생의 여지가 있는 메서드는 throws를 사용하여 오류를 내포하는 함수임을 표시한다.

class CoffeeMachine {
    let coffeePrice: Int = 100
    var coffeeStock: Int = 5
    var depositedCoins: Int = 200
    
    
    // 동전 투입 메서드
    func insertCoins(coins: Int) throws {
    
    // 투입된 동전이 0보다 크지않으면 invalidSelection 에러를 던진다.
        guard coins > 0 else {
            throw CoffeeMachineError.invalidInput
        }
        
        // 에러가 없을 시 정상 처리한다.
        self.depositedCoins += coins
       print("\(coins)원 동전 투입되었습니다.")
    }
    
    
    // 커피 판매 메서드
    func vendCoffee(numberOfCoffees: Int) throws -> String {
    
        // 구입하는 커피 개수가 커피재고보다 크면 insufficienCoffes에러를 던진다.
        guard numberOfCoffees >= coffeeStock else {
            throw CoffeeMachineError.insufficienCoffes
        }
        
        // 커피의 총 금액이 디파짓된 코인보다 크면 insufficientFunds 에러를 던진다.
        guard numberOfCoffees * coffeePrice <= depositedCoins else {
            let requiredCoins = numberOfCoffees * coffeePrice - depositedCoins
            throw CoffeeMachineError.insufficientFunds(requiredCoins: requiredCoins)
        }
        
        // 에러가 없을 시 정상 처리한다.
        let totalPrice = numberOfCoffees * coffeePrice
        
        self.depositedCoins -= totalPrice
        self.coffeeStock -= numberOfCoffees
        
        return "\(numberOfCoffees)잔의 커피 가격은 \(totalPrice)입니다."
    }
}


🔨 오류 처리

오류가 던져지는 것에 대비하여 던져진 오류를 처리하기 위한 코드도 작성해야 한다.
예를 들어 던져진 오류가 무엇인지 판단하여 다시 문제를 해결한다든지, 다른 방법으로 시도해 본다든지, 사용자에게 오류를 알리고 사용자에게 선택 권한을 넘겨주어 다음에 어떤 동작을 하게 할 것인지 결정하도록 유도하는 등의 코드를 작성해야 한다.
오류발생의 여지가 있는 throws 함수(메서드)try를 사용하여 호출해야한다.

do-catch

모든 오류 케이스에 대응한다.

// CoffeeMachine class 인스턴스
let machine = CoffeeMachine()


// 사용 예시
do {
    try machine.insertCoins(coins: 0)
} catch CoffeeMachineError.invalidInput {
    print("입력이 잘못되었습니다")
} catch CoffeeMachineError.insufficienCoffes {
    print("수량이 부족합니다")
} catch CoffeeMachineError.insufficientFunds(let moneyNeeded) {
    print("\(moneyNeeded)원이 부족합니다")
} catch {
    print("예상치 못한 오류가 발생했습니다")
}

// 출력값: 입력이 잘못되었습니다.


// 하나의 catch 블럭에서 switch 구문을 사용하여 오류를 분류할 수도 있다.
do {
    try machine.insertCoins(coins: 5)
} catch let error as CoffeeMachineError {
    switch error {
    case .invalidInput:
        print("유효하지 않은 선택입니다")
    case .insufficienCoffes:
        print("원두가 부족합니다")
    case .insufficientFunds(let moneyNeeded):
        print("\(moneyNeeded)원이 부족합니다")
    default:
        print("예상치 못한 오류가 발생했습니다")
    }
}
// 출력값: 10원 동전 투입되었습니다.


// 케이스별로 오류처리 할 필요가 없으면 catch 구문 내부를 간략하게 작성해도 된다. 
do {
    try machine.insertCoins(coins: 10)
} catch {
    print(error)
} 
// 출력값: invalidInput

try?

별도의 오류처리 결과를 통보받지 않고 오류가 발생했으면 결과값을 nil로 돌려받고, 정상동작을 하면 정상 반환값을 옵셔널 타입으로 돌려받는다.

var result: String?
result = try? machine.vendCoffee(numberOfCoffees: 1)
print(result) // 출력값: Optional("1잔의 커피 가격은 100입니다.")

result = try? machine.vendCoffee(numberOfCoffees: 2)
print(result) // 출력값: nil

try!

오류가 발생하지 않을 것이라는 확신이 있을 때 사용하면 정상동작 후에 바로 옵셔널이 아닌 결과값을 돌려받지만 오류가 발생하면 런타임 오류가 발생하여 애플리케이션 동작이 중지된다.

result = try! machine.vendCoffee(numberOfCoffees: 1)
print(result) 
// 출력값: Optional("1잔의 커피 가격은 100입니다.")

result = try! machine.vendCoffee(numberOfCoffees: 1)
// Error: 'try!' expression unexpectedly raised an error

0개의 댓글