본문 바로가기
iOS/Swift 문법 심화 학습

오류 처리 [ error handling ]

by 황민우 2022. 2. 4.

정의

- 오류처리는 프로그램에서 발생한 에러를 받고 대응하는 과정입니다.

- Swift에서 오류를 표기하는 방법으로 Error 프로토콜과 열거형을 사용합니다.


오류 표현

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

오류처리 예제

오류처리 생성

- 자판기가 일으킬 수 있는 오류사항을 표현한 VendingMachineError 열거형

- 오류사항은 다음과 같습니다.

더보기

1, 금액 투입의 오류

2, 잔액 부족

3, 품절

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

 

클래스 생성

class VendingMachine {
    let itemPrice: Int = 100
    var itemCount: Int = 5
    var deposited: Int = 0
}

 

메서드 생성 1 : 돈을 받는 메서드

- 메서드 안에서 오류가 발생했다고 자신을 호출시킨 메서드나 해당 블록에 throw를 사용하여 오류를 발생시킵니다.

- 메서드의 이름 옆에 throws 키워드를 작성해 오류가 발생할 여지가 있음을 표현합니다.

- 오류가 없으면 받은 금액을 출력하는 메시지를 보내고, 돈이 0원 이하면 오류를 발생시키도록 메서드를 구현했습니다.

func receiveMoney(_ money: Int) throws {
        
        // 입력한 돈이 0이하면 오류를 던집니다
        guard money > 0 else {
            throw VendingMachineError.invalidInput
        }
        
        // 오류가 없으면 정상처리를 합니다
        self.deposited += money
        print("\(money)원 받음")
}

 

메서드 생성 2 : 물건 판매 메서드

- 첫 번째 메서드와 마찬가지로 throws 키워드를 명시해 오류가 발생할 수 있음을 표현합니다.

- 물건의 수량, 금액, 요구 수량에 해당하는 오류를 처리하는 코드들을 구현하고, 오류가 없으면 정상 처리하도록 코드를 작성합니다.

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.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를 사용해 호출해야 합니다.

- 오류 발생에 대비해 do-catch문을 함께 사용합니다.

 

try

- 가장 정석적인 방법으로 모든 오류 종류에 대응할 수 있습니다. 

- 먼저 do 블록 안에 try 구문을 작성하고, catch로 구문을 마무리해줍니다.
- do 블록 안에 구문에서 오류가 발생해,

  함수가 던져지면(throw) catch 뒤에 오는 오류 종류와 일치하는 구문을 실행합니다.

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

 

switch case문을 이용한 try

- 정석적인 try 문과 동일합니다.

- switch case문을 이용해 오류 종류에 대해 분류할 수 있습니다.

- 주석처리되어있는 (let error) 상수 부분을 통해 catch 구문으로 상수를 암시적으로 보낼 수 있습니다.

- 즉, 필요에 의해서 전달 인자의 이름을 변경할 수 있습니다. 

do {
    try machine.receiveMoney(300)
} catch /*(let error)*/ {
    
    switch error {
    case VendingMachineError.invalidInput:
        print("입력이 잘못되었습니다")
    case VendingMachineError.insufficientFunds(let moneyNeeded):
        print("\(moneyNeeded)원이 부족합니다")
    case VendingMachineError.outOfStock:
        print("수량이 부족합니다")
    default:
        print("알수없는 오류 \(error)")
    }
}

 

오류 분류 생략

- 케이스별로 오류처리 분류를 할 필요가 없다면, 다음과 같이 catch내부 구문을 간략하게 작성할 수 있습니다.

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

 

try?

- 별도의 오류처리 결과를 통보받지 않고, 오류가 발생했으면 결괏값을 nil로 돌려받을 수 있습니다.

- 정상 동작 후에는 옵셔널 타입으로 정상 반환 값을 돌려받습니다.

- do catch를 쓰지 않고 오류를 던져주는 메서드를 호출해 nil값을 받거나 옵셔널 타입의 정상 결괏값을 받습니다.

정상동작
result = try? machine.vend(numberOfItems: 2)
print(result as Any) // Optional("2개 제공함")

오류발생
result = try? machine.vend(numberOfItems: 2)
print(result as Any) // nil

 

try!

- 오류가 발생하지 않을 것이라는 확신을 가질 때 사용합니다.

- try! 를 사용하여 정상 동작 후에 바로 결과값을 돌려받습니다.

- 오류가 발생하면 런타임 오류가 발생하여 동작이 중지됩니다.

- 정상동작 후에는 일반 타입의 정상 반환 값을 돌려받습니다.

정상동작
result = try! machine.vend(numberOfItems: 1)
print(result as Any) // 1개 제공함

오류발생
result = try! machine.vend(numberOfItems: 1) // 런타임 오류 프로그램 동작 중지

내용 출처

https://www.youtube.com/watch?v=l0fGtNnNsJg&list=PLz8NH7YHUj_ZmlgcSETF51Z9GSSU6Uioy&index=28 

 

'iOS > Swift 문법 심화 학습' 카테고리의 다른 글

제네릭 [ Generic ]  (0) 2022.02.08
고차함수 [ map, filter, reduce ]  (0) 2022.02.07
열거형 [ enum ]  (0) 2022.02.03
클래스 [ Class ]  (0) 2022.02.03
구조체 [ Struct ]  (0) 2022.02.03

댓글