본문 바로가기
etc/Swift

오류 처리

by IT learning 2021. 5. 28.
728x90

 

오늘은 오류처리에 대해서 공부하였다.

보통 Error 프로토콜과 열거형을 통해서 오류를 표현한다

 

정의

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

코드는 이렇게 작성한다. 보통 열거형으로 사용한다.

 

자판기 동작 오류의 종류를 표현한 VendingMachineError 열거형

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

이렇게 에러의 종류들을 생성해준다.

 

함수에서 발생한 오류 던지기

class VendingMachine {
    let itemPrice: Int = 100
    var itemCount: Int = 5
    var deposited: Int = 0
    
    // 돈 받기 메서드
    func reciveMoney(_ 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
        }
        
        // 구매하려는 수량보다 미리 넣어둔 돈이 적으면 오류를 던집니다.
        guard numberOfItemsToVend * itemPrice <= deposited else {
            let moneyNeeded: Int
            moneyNeeded = numberOfItemsToVend * itemPrice - deposited
            
            throw VendingMachineError.insufficientFund(moneyNeeded: moneyNeeded)
        }
        
        // 구매하려는 수량보다 요구하는 수량이 많으면 오류를 던집니다.
        guard itemCount >= numberOfItemsToVend else {
            throw VendingMachineError.outOfStock
        }
        
        // 오류가 없으면 정상처리를 합니다
        let totalPrice = numberOfItemsToVend * itemPrice
        
        self.deposited -= totalPrice
        self.itemCount -= numberOfItemsToVend
        
        return "\(numberOfItemsToVend)개 제공함"
    }
}

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


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

코드가 좀 길다. 천천히 보자.

먼저 돈 받기 메서드가 보인다. 입력한 돈이 0이하면 오류를 던진다. 던지기는 throw 로 던지면 된다. 오류가 없다면 정상처리를 해준다.

그 다음 물건 팔기 메서드가 보인다. 그 다음에도 이러한 에러들을 걸러내는 작업을 한다.

그렇게 아무런 에러가 없을 경우, 정상으로 처리 한다.

 

오류처리

오류발생의 여지가 있는 throws 함수는 try를 사용하여 호출애야 한다.

 

* do-catch

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

do {
    try machine.reciveMoney(300)
} catch /* (let error) */ { // 이게 암시적으로 넘어오기 때문에 주석처리 함
    switch error {
    case VendingMachineError.invalidInput:
        print("입력이 잘못되었습니다.")
    case VendingMachineError.insufficientFund(let moneyNeeded):
        print("\(moneyNeeded)원이 부족합니다")
    case VendingMachineError.outOfStock:
        print("수량이 부족합니다")
    default:
        print("알수없는 오류 \(error)")
    }
} // 300원 받음

위 코드를 보자. 윗 문단 코드는 단순히 do - catch 구문을 이용한 코드이다. 조금은 복잡하다.

아래 문단 코드는 do - catch 에 switch 구문을 추가해 에러를 나눴다. 근데 이것 마저도 복잡하다. 짜증이 난다.

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


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

그렇다면 이렇게 간소화 해보자. 그냥 에러에 내용은 중요하지 않으니까 인스턴스만 보고 에러가 어떤건지 찾아낼수도 있고, 아니면 아예 에러를 찾아보지도 않아도 되긴하다..

 

try? 와 try!

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

result = try? machine.vend(numberOfItems: 2)
result // nil

// try!
// 오류가 발생하지 않을 것이라는 강력한 확신을 가질 때
// try!를 사용하면 정상동작 후에 바로 결과값을 돌려받습니다
// 오류가 발생하면 런타임 오류가 발생하여
// 애플리케이션 동작이 중지됩니다

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

//result = try! machine.vend(numberOfItems: 1)

옵셔널로 이 문제를 해결할 수 있다.

먼저 nil? 을 보자. 별도의 오류처리 결과를 통보받지 않고 오류가 발생했으면 결과값을 nil로 돌려받을 수 있다.

try!의 경우 무조건 에러가 발생하지 않을것이라는 생각으로 정상동작 후에 결과값을 돌려받는다. 하지만 이러다가 에러가 발생하면 애플리케이션 자체가 중지된다.

728x90

'etc > Swift' 카테고리의 다른 글

추가적으로 공부해야할 것들  (0) 2021.05.28
고차함수  (0) 2021.05.28
익스텐션(Extension)  (0) 2021.05.28
프로토콜(Protocol)  (0) 2021.05.28
assert와 guard  (0) 2021.05.28

댓글

IT_learning's Commit