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)
}
요런 식으로 간략화해서 사용하자.
별도의 오류처리 결과를 통보받지 않고 오류가 발생했으면 결과값을 nil로 돌려받을 수 있다. 정상동작한다면 옵셔널 타입의 정상 반환값을 돌려 받는다.
result = try? machine.vend(numberOfItems: 2)
result // Optional("2개 제공함") 또는 nil
위의 경우 정상동작하면 Optional("2개 제공함")
이 반환되고, 오류가 발생하면 nil
이 반환된다.
오류가 발생하지 않을 것이라는 강력한 확신을 가질 때 try!를 사용하면 정상동작 후에 바로 일반 타입의 정상 반환값을 돌려받는다. 하지만 만약 오류가 발생하면 런타임 오류로 애플리케이션 동작이 중지된다.
result = try! machine.vend(numberOfItems: 1)
result // 1개 제공함
야곰의 스위프트 기본 문법 강좌를 수강하며 작성한 내용입니다.