[Swift] 오류처리

선주·2022년 4월 11일

Swift

목록 보기
14/20

📌 오류처리

Swift에서 오류는 주로 Error 프로토콜과 열거형을 통해 처리한다.

오류가 발생하면 throw를 이용해 자신을 호출한 지점에 오류를 던져준다. 오류 발생의 여지가 있는 메서드는 throws를 사용하여 오류를 내포하는 함수임을 표시한다.

enum VendingMachineError: Error {
    case invalidInput
    case insufficientFunds(moneyNeeded: Int)
    case outOfStock
}

예를 들면 위의 VendingMachineError는 자판기를 사용하면서 발생하는 오류를 정의해둔 것이다.

오류 던지기

class VendingMachine {
    let itemPrice: Int = 100
    var itemCount: Int = 5
    var deposited: Int = 0
    
    // 돈 받기 메서드
    func receiveMoney(_ money: Int) throws {
        
        // 입력한 돈이 0이하면 오류를 던진다
        guard money > 0 else {
            throw VendingMachineError.invalidInput
        }
        
        // 오류가 없으면 정상처리를 한다
        self.deposited += money
        print("\(money)원 받음")
    }
    
    // 물건 팔기 메서드
    func vend(numberOfItems numberOfItemsToVend: Int) throws -> String {
        
        // 원하는 아이템의 수량이 잘못 입력되었으면 오류를 던진다
        guard numberOfItemsToVend > 0 else {
            throw VendingMachineError.invalidInput
            // vend 메서드는 리턴값이 String으로 정해져 있지만
            // 오류가 던지는 경우는 리턴값을 만들지 않아도 된다
        }
        
        // 구매하려는 수량보다 미리 넣어둔 돈이 적으면 오류를 던진다
        guard numberOfItemsToVend * itemPrice <= deposited else {
            let moneyNeeded: Int
            moneyNeeded = numberOfItemsToVend * itemPrice - deposited
            
            throw VendingMachineError.insufficientFunds(moneyNeeded: moneyNeeded)
        }
        
        // 구매하려는 수량보다 요구하는 수량이 많으면 오류를 던진다
        guard itemCount >= numberOfItemsToVend else {
            throw VendingMachineError.outOfStock
        }
        
        // 오류가 없으면 정상처리를 한다
        let totalPrice = numberOfItemsToVend * itemPrice
        
        self.deposited -= totalPrice
        self.itemCount -= numberOfItemsToVend
        
        return "\(numberOfItemsToVend)개 제공함"
    }
}


// 판매 결과를 전달받을 변수
var result: String?

오류 받기

오류를 던질 수도 있지만 오류가 던져지는 것에 대비하여 던져진 오류를 처리하기 위한 코드도 필요하다.

오류발생의 여지가 있는 throws 함수(메서드)는 try를 사용하여 호출해야 한다.

// 자판기 인스턴스
let machine: VendingMachine = VendingMachine()

do {
    try machine.receiveMoney(0)
} catch VendingMachineError.invalidInput {
    print("입력이 잘못되었습니다")
} catch VendingMachineError.insufficientFunds(let moneyNeeded) {
    print("\(moneyNeeded)원이 부족합니다")
} catch VendingMachineError.outOfStock {
    print("수량이 부족합니다")
} // 입력이 잘못되었습니다

만약 machine.receiveMoney(0)에서 오류가 발생해서 오류를 던지면 catch문에서 오류를 받는다.


✔️ 간략화

하지만 이렇게 경우 하나하나 핸들링할 필요가 없다면 굳이 이렇게 하는 게 더 복잡하다.

do {
    result = try machine.vend(numberOfItems: 4)
} catch {
    print(error)
} 

요런 식으로 간략화해서 사용하자.


✔️ try?

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

result = try? machine.vend(numberOfItems: 2)
result // Optional("2개 제공함") 또는 nil

위의 경우 정상동작하면 Optional("2개 제공함")이 반환되고, 오류가 발생하면 nil이 반환된다.


✔️ try!

오류가 발생하지 않을 것이라는 강력한 확신을 가질 때 try!를 사용하면 정상동작 후에 바로 일반 타입의 정상 반환값을 돌려받는다. 하지만 만약 오류가 발생하면 런타임 오류로 애플리케이션 동작이 중지된다.

result = try! machine.vend(numberOfItems: 1)
result // 1개 제공함


야곰의 스위프트 기본 문법 강좌를 수강하며 작성한 내용입니다.

profile
기록하는 개발자 👀

0개의 댓글