관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift 공식 문서] 16. Error Handling (오류 처리) 본문

swift 공식 문서

[iOS - swift 공식 문서] 16. Error Handling (오류 처리)

jake-kim 2021. 7. 13. 23:10

Error Handling

  • 개념: 프로그램의 오류 조건에 응답하고 복구하는 프로세스
  • Swift에서는 런타임에 복구 가능한 오류를 다음 방법으로 처리 throwing, catching, propagating, manipulating 

Throwing Error (에러 던지기)

  • Swift에서의 오류는 Error protocol을 conform하는 값으로 정의
enum VendingMachineError: Error {
    case invalidSelection
    case insufficientFunds(coinsNeeded: Int)
    case outOfStock
}

Error Handling

  • 함수에서 오류가 발생하면 프로그램의 흐름이 변경되므로 코드에서 오류가 발생할 수 있는 위치를 빠르게 식별해야 하는데, 이 부분 표시를 try키워드로 표현 (try?, try!)

함수에 throws키워드를 사용하여 오류 던지기

  • '->' 전에 throws 키워드 작성
func canThrowErrors() throws -> String
  • throws, throw 사용 부분: throws키워드는 함수에 한번만 선언, throw는 return과 같은 중단될 부분에 사용
enum VendingMachineError: Error {
    case invalidSelection
    case insufficientFunds(coinsNeeded: Int)
    case outOfStock
}

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

class VendingMachine {

    var inventory = [
        "Candy Bar": Item(price: 12, count: 7),
        "Chips": Item(price: 10, count: 4)
    ]

    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.count <= coinsDeposited else {
            throw VendingMachineError.insufficientFunds(coinsNeeded: item.price - coinsDeposited)
        }

        coinsDeposited -= item.price

        var newItem = item
        newItem.count -= 1
        inventory[name] = newItem
        print("Despensing \(name)")
    }

}
  • 해당 함수를 부르는 곳에서도 throws, try 사용
let favoriteSnacks = [
    "Alice": "Chips",
    "Bob": "Licorice",
    "Eve": "Pretzels",
]
func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
    let snackName = favoriteSnacks[person] ?? "Candy Bar"
    try vendingMachine.vend(itemNamed: snackName)
}

사용하는 쪽에서 Do-Catch로 오류 처리

  • do - try - catch 구조: do 절의 코드에서 오류가 발생하면 catch중 어느것이 오류를 처리할 것인지 결정
do {
    try expression
    statements
} catch pattern 1 {
    statements
} catch pattern 2 where condition {
    statements
} catch pattern 3, pattern 4 where condition {
    statements
} catch {
    statements
}
  • 예시
func eat(item: String) throws {
    do {
        try vendingMachine.vend(itemNamed: item)
    } catch VendingMachineError.invalidSelection, VendingMachineError.insufficientFunds, VendingMachineError.outOfStock {
        print("Invalid selection, out of stock, or not enough money.")
    }
}

Optinoal으로 반환하는 try

  • try? 키워드 사용: 오류 발생 시 nil 반환
func someThrowingFunction() throws -> Int {
    // ...
}

let x = try? someThrowingFunction()

let y: Int?
do {
    y = try someThrowingFunction()
} catch {
    y = nil
}
  • throw대신 defer문 사용
    • 모든 파일을 읽고 파일을 close하는 예제
func processFile(filename: String) throws {
    if exists(filename) {
        let file = open(filename)
        defer {
            close(file)
        }
        while let line = try file.readline() {
            // Work with the file.
        }
        // close(file) is called here, at the end of the scope.
    }
}

* 참고

https://docs.swift.org/swift-book/LanguageGuide/ErrorHandling.html

Comments