본문 바로가기
TIL(Today I Learned)

Swift 에러 처리

by 승환파크 2025. 3. 14.

에러 처리는 프로그램에서 발생할 수 있는 예외적인 상황을 감지하고 대응하는 중요한 프로세스이다.

 

에러 표현과 던지기(Peoresenting and Throwing Errors)

Swift에서 에러는 Error프로토콜을 준수하는 타입으로 표현된다. 열거형을 사용하면 다양한 에러 상황을 모델링하고 관련 값을 포함할 수 있다.

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

에러를 발생시키려면 thorw 키워드를 사용한다.

thorw VendingMachineError.insufficientFunds(coinsNeeded: 5)

 

에러 처리 방법(Handling Errors)

Swift에서는 에러를 처리하는 네 가지 방식을 제공한다.

1. 에러 전파

2. do-catch 구문 사용

3. 옵셔널 값으로 변환(try?)

4. 에러 발생 가능성 무시(try!)

1. 에러 전파(Propagating Errors)

throws 키워드를 사용하여 에러가 발생할 수 있음을 선언한다. 이 방법은 주로 에러가 발생할 가능성이 있는 함수에서 사용되며, 에러를 호출한 함수에서 처리해야 한다.

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

이 함수는 호출하는 쪽에서 try를 사용하여 에러를 처리해야 한다.

try vend(itemNamed: "Chips")

2. do-catch 구문 사용

do-catch를 사용하여 특정 에러에 대해 대응할 수 있다. 이 방법은 여러 가지 에러를 분류하고 각각의 상황에 맞게 대응할 때 유용하다.

do {
    try vend(itemNamed: "Chips")
    print("구매 완료")
} catch VendingMachineError.invalidSelection {
    print("잘못된 선택입니다.")
} catch VendingMachineError.outOfStock {
    print("재고가 없습니다.")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {
    print("잔액이 부족합니다. 추가로 \(coinsNeeded) 코인을 넣어주세요.")
} catch {
    print("알 수 없는 에러: \(error)")
}

3. 옵셔널 값으로 변환(try?)

에러가 발생하면 nil을 반환하도록 할 수도 있다. 이 방법은 에러 발생 여부와 관계없이 특정 동작을 간결하게 처리할 때 사용된다.

let result = try? vend(itemNamed: "Chips")

에러가 발생하면 result는 nil이 되며, 발생하지 않으면 함수의 반환 값을 받는다.

4. 에러 발생 가능성 무시(try!)

에러가 발생하지 않는다고 확신하는 경우 try!를 사용할 수 있다. 하지만 런타임 에러가 발생할 수 있으므로 주의해야 한다.

let item = try! vend(itemNamed: "Candy Bar")

이 방법은 주로 앱의 필수적인 동작에서 실패할 가능성이 없는 경우에만 사용해야 한다.

 

에러 타입 지정(Specifying the Error Type)

Swift에서는 특정 에러 타입을 지정하여 보다 안전하게 에러를 관리할 수 있다.

enum StatisticsError: Error {
    case noRatings
    case invalidRating(Int)
}

특정 에러 타입을 던지는 함수를 정의할 수 있습니다.

func summarize(_ ratings: [Int]) throws(StatisticsError) {
    guard !ratings.isEmpty else { throw .noRatings }
    
    var counts = [1:0, 2:0, 3:0]
    for rating in ratings {
        guard rating > 0 && rating <= 3 else { throw .invalidRating(rating) }
        counts[rating]! += 1
    }
}

이 함수는 StatistcsError 타입의 에러만 발생할 수 있다. 이를 통해 예상치 못한 다른 에러를 방지할 수 있다.

 

정리 작업 지정(Specifying Cleanup Actions)

defer 구문을 사용하면 코드 블록이 종료되기 직전에 특정 작업을 실행할 수 있다. 이 방법은 파일을 열고 닫거나, 네트워크 연결을 관리할 때 유용하게 활용된다.

func processFile(filename: String) throws {
    let file = open(filename)
    defer {
        close(file)
    }
    while let line = try file.readline() {
        // 파일 처리
    }
}

defer의 특징

defer는 코드 블록이 종료될 때 실행되고, 여러 개의 defer 구문이 있을 경우 선언된 역순으로 실행된다. 에러가 발생해도 defer 구문은 실행되며 함수가 return 되거나 throw를 만나더라도 defer는 반드시 실행된다.

func example() {
    defer { print("1") }
    defer { print("2") }
    defer { print("3") }
    print("Function Execution")
}

example()
// 출력
// Function Execution
// 3
// 2
// 1

이처럼 defer는 가장 마지막에 정의된 것이 가장 먼저 실행된다.

'TIL(Today I Learned)' 카테고리의 다른 글

Swift의 ARC  (0) 2025.03.01
2025.02.24 Today I Learned  (0) 2025.02.24
2025.02.14 Today I Learned  (0) 2025.02.14
2025.02.05 Today I Learned  (0) 2025.02.05
2025.01.24 Today I Learned  (0) 2025.01.24