[Swift] Error Handling

Charlie·2022년 9월 13일
0

에러 처리

스위프트에서는 런타임에 에러가 발생한 경우 에러를 처리가히 위해 에러의 발생(throwing), 감지(catching), 증식(propagating), 조작(manipulating)을 지원하는 클래스를 제공한다.

에러의 표시와 발생

Swift에서 에러는 Error 프로토콜을 따르는 타입의 값으로 표현된다. Error 프로토콜은 비어있는데, 이 프로토콜을 따르는 타입이 에러 처리를 위해 사용될 수 있다는 것을 가르킨다.
Swift의 열거형은 특히 관련된 에러를 그룸화하고 추가적인 정보를 제공하기에 적합하다.
예를들어, 게임 자판기의 동작 에러와 관련한 에러를 다음과 같이 표현할 수 있다.

enum VendingMachineError: Error {
    case invalidSelection
    case insufficientFunds(cinsNeeded: Int)
    case outOfStock
}

에러를 위와 같이 선언하고 5개의 코인이 더 필요하다는 에러를 다음과 같이 발생시킬 수 있다.

throw VendingMachineError.insufficientFunds(coinsNeeded: 5)

에러 처리

에러가 발생하면 특정 코드 영역이 해당 에러를 처리하도록 해야한다. Swift에서는 4가지 방법으로 에러를 처리할 수 있다.

  • 에러가 발생한 함수에서 리턴값으로 에러를 반환해 해당 함수를 호출한 코드에서 에러를 처리
  • do-catch 문 사용
  • 옵셔널 값을 반환하는 방법
  • assert를 사용해 강제로 크래쉬를 발생시키는 방법

에러를 발생시키는 함수 사용하기

어떤 메소드가 에러를 발생 시킬 수 있다는 것을 알리기 위해서 다음과 같이 throw 키워드를 함수 선언부의 파라미터 뒤에 붙일 수 있다.

func canThrowErrors() throw -> String

이러한 함수를 throwing function 이라고 하고 함수 내부에서 에러를 만들어 함수가 호출된 곳으로 전달한다.

오직 throwing function만이 에러를 발생시킬 수 있다. 만약 throwing function이 아닌 함수에서 throw가 발생한다면 반드시 그 함수내에서 throw에 대해 처리돼야 한다.

struct Item {
    var price: Int
    var count: Int
}

class VendingMachine {
    var inventory = [
        "Candy Bar": Item(price: 12, count: 7),
        "Chips": Item(price: 10, count: 4),
        "Pretzels": Item(price: 7, count: 11)
    ]
    var coinsDeposited = 0

    func vend(itemNamed name: String) throws {
        guard let item = inventory[name] else {
            throw VendingMachineError.invalidSelection
        }

        guard item.count > 0 else {
            throw VendingMachineError.outOfStock
        }

        guard item.price <= coinsDeposited else {
            throw VendingMachineError.insufficientFunds(coinsNeeded: item.price - coinsDeposited)
        }

        coinsDeposited -= item.price

        var newItem = item
        newItem.count -= 1
        inventory[name] = newItem

        print("Dispensing \(name)")
    }
}

vend(itemNamed:) 메소드의 구현에서 guard구문을 사용해 에러가 발생하면 함수에서 에러를 발생시키고 빠르게 함수를 탈출할 수 있도록 한다. 해당 메소등는 에러를 발생시키기 때문에 이 메소드를 호출하는 메소드는 반드시 do-catch, try?, try! 등의 구문을 사용해 에러를 처리해야 한다.

Do-catch를 이용해 에러 처리

do-catch를 이용해 에러를 처리하는 코드 블럭을 작성할 수 있다.

do {
    try expression
    statements
} catch pattern 1 {
    statements
} catch pattern 2 where condition {
    statements
} catch {
    statements
}

catch 구문 뒤에 어떤 에러인지 적고 그것을 어떻게 처리할지 명시할 수 있고 만약 catch 구문 뒤에 에러 종류를 명시하지 않으면 발생하는 모든 에러를 지역 상수인 error로 바인딩한다.

에러를 옵셔널 값으로 변환하기

try? 구문을 사용해 에러를 옵셔널 값으로 변환할 수 있고, 에러가 발생한다면 nil이 된다.
try?는 만약 발생하는 모든 에러를 같은 방법으로 처리하고 싶을 때 사용한다. 예를 들어, 다음 코드는 데이터를 가져오는 여러 접근 방법을 시도하는데 접근 방법이 모두 실패하면 nil을 반환한다.

func fetchData() -> Data? {
    if let data = try? fetchDataFromDisk() { return data }
    if let data = try? fetchDataFromServer() { return data }
    return nil
}

에러 발생을 중지하기

메소드에서 에러가 발생되지 않을 것이라고 확신하는 경우 try!를 사용할 수 있다.

Reference

The Swift Language Guide

profile
Hello

0개의 댓글