[Swift] 오류처리 (Error Handling)

김형근·2024년 7월 25일

[Swift] 문법

목록 보기
19/20

🍎 Swift에서의 오류 처리 (Error Handling)

  • 코드의 신뢰성을 높이고 예상치 못한 상황에 대처하는 데 중요합니다.
  • Swift는 'Error' 프로토콜을 사용하여 오류를 표현하고, 주로 열거형 (enum) 을 통해 다양한 오류 상태를 정의합니다.

🍏 오류 처리

  • Swift에서 오류(Error)는 Error 라는 프로토콜을 준수하는 타입의 값을 통해 표현됩니다. Error 프로토콜은 사실상 요구사항이 없는 빈 프로토콜일 뿐이지만, 오류를 표현하기 위한 타입(주로 열거형)은 이 프로토콜을 채택합니다.

🍏 오류 표현

  • 오류를 표현하기 위해 Error 프로토콜을 채택한 열거형을 사용합니다.
  • 'VendingMachineError' 열거형은 자판기 동작 중 발생할 수 있는 다양한 오류를 나타냅니다.
// 자판기 동작 오류의 종류를 표현한 VendingMachineError 열거형
enum VendingMachineError: Error {
    // 잘못된 입력을 나타내는 오류
    case invalidInput
    // 돈이 부족함을 나타내는 오류 (부족한 금액을 포함)
    case insufficientFunds(moneyNeeded: Int)
    // 재고가 부족함을 나타내는 오류
    case outOfStock
}

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

  • 오류가 발생할 가능성이 있는 함수는 throws 키워드를 사용하여 오류를 던질 수 있음을 표시합니다.
// 자판기 클래스
class VendingMachine {
    let itemPrice: Int = 100 // 아이템 가격
    var itemCount: Int = 5 // 아이템 수량
    var deposited: Int = 5 // 투입된 돈
    
    // 돈 받기 메서드
    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
        }
        // 구매하려는 수량보다 미리 넣어둔 돈이 적으면 오류를 던집니다.
        guard numberOfItemsToVend * itemPrice <= deposited else {
            let 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)개 제공함"
    }
}

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

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

🍏 오류 처리

  • 오류가 발생할 가능성이 있는 함수(메서드)를 호출할 때는 try, try?, try! 를 사용하여 오류를 처리합니다.

  • 오류를 던질 수도 있지만, 오류가 던져지는 것에 대비하여 던져진 오류를 처리하기 위한 코드도 작성해야 합니다. 예를 들어, 던져진 오류가 무엇인지 판단하여 다시 문제를 해결하거나, 다른 방법으로 시도해 보거나, 사용자에게 오류를 알리고 선택 권한을 넘겨주는 등의 코드를 작성해야 합니다.

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


🧃 do-catch

  • 오류가 발생할 가능성이 있는 코드를 do-catch 구문으로 감싸고, 발생한 오류를 catch 블록에서 처리합니다.

🧃 가장 정석적인 방법으로 모든 오류 케이스에 대응

do {
    // 돈 받기 메서드 호출, 0원을 입력하여 오류를 발생시킵니다.
    try machine.receiveMoney(0)
} catch VendingMachineError.invalidInput {
    // 입력 오류를 처리하는 catch 블록
    print("입력이 잘못되었습니다.")
} catch VendingMachineError.insufficientFunds(let moneyNeeded) {
    // 금액 부족 오류를 처리하는 catch 블록
    print("\(moneyNeeded)원이 부족합니다.")
} catch VendingMachineError.outOfStock {
    // 재고 부족 오류를 처리하는 catch 블록
    print("수량이 부족합니다.")
} // 출력: 입력이 잘못되었습니다.

🧃 하나의 catch 블럭에서 switch 구문을 사용하여 오류를 분류

do {
    // 돈 받기 메서드 호출, 정상적으로 300원을 받습니다.
    try machine.receiveMoney(300)
} catch {
    // 기타 모든 오류를 처리하는 catch 블록
    switch error {
    case VendingMachineError.invalidInput:
        print("입력이 잘못되었습니다.")
    case VendingMachineError.insufficientFunds(let moneyNeeded):
        print("\(moneyNeeded)원이 부족합니다.")
    case VendingMachineError.outOfStock:
        print("수량이 부족합니다.")
    default:
        print("알 수 없는 오류 \(error)")
    }
} // 출력: 300원 받음

🧃 딱히 케이스별로 오류처리 할 필요가 없다면 catch 구문 내부를 간략화해도 무방

do {
    // 물건 팔기 메서드 호출, 4개를 팔려고 시도하여 오류를 발생시킵니다.
    result = try machine.vend(numberOfItems: 4)
} catch {
    // 발생한 오류를 출력합니다.
    print(error)
} // 출력: insufficientFunds(100)

🧃 케이스별로 오류처리 할 필요가 없으면 do 구문만 써도 무방

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

🧃 try? 와 try!

  • try? 는 오류가 발생하면 결과값을 'nil' 로 돌려받고, 정상 동작 후에는 옵셔널 타입으로 결과값을 돌려받습니다.
// 물건 팔기 메서드 호출, 정상적으로 2개를 제공합니다.
result = try? machine.vend(numberOfItems: 2)
print(result) // Optional("2개 제공함")

// 물건 팔기 메서드 호출, 재고 부족으로 인해 nil을 반환합니다.
result = try? machine.vend(numberOfItems: 2)
print(result) // nil
  • try! 는 오류가 발생하지 않을 것이라는 확신이 있을 때 사용합니다. 오류가 발생하면 런타임 오류가 발생하여 애플리케이션 동작이 중지됩니다.
// 물건 팔기 메서드 호출, 정상적으로 1개를 제공합니다.
result = try! machine.vend(numberOfItems: 1)
print(result) // 1개 제공함
profile
꾸준히 기록하기

0개의 댓글