티스토리 뷰

에러 핸들링은 프로그램 속 에러 상태에 반응하고 복구하기 위한 과정입니다. 스위프트는 런타임 에러를 커버할 수 있는 자원을 제공합니다. 몇몇 연산은 완벽한 결과문 또는 쓸만한 아웃풋을 항상 준다는 보장을 할 수 없지만 연산이 실패했을 때 적절하게 반응하기 위해  어떤 문제로 실패하게 되었는지 이해하는 것은 유용합니다. 

 

Representing and Throwing Errors

스위프트에서 에러는 Error 프로토콜을 준수하는 타입의 값으로 표현됩니다. 이 프로토콜은 이 타입이 에러 핸들링에 사용될 수 있다는 것을 나타냅니다. 열거형은 비슷한 에러 컨디션을 그룹화하기에 적합합니다. 

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

에러를 던지는 것은 예상치 못한 상황일때나 일반적인 코드 흐름이 진행되지 않을 때를 가리킵니다. throw 를 사용하여 에러를 던질 수 있습니다. 예를 들어 예제 코드는 에러를 던져 VendingMachine이 5개의 추가 코인이 필요하다는 것을 가리킵니다.

throw VendingMachineError.insufficientFunds(coinsNeeded: 5)

 

Handling Errors

에러가 던져졌을 때 코드의 어떤 부분은 반드시 에러를 다뤄야 합니다. 예를 들어 문제를 수정하기 위해 다른 방법으로 시도한다든지, 또는 유저에게 실패한 이유를 알려주든지 말입니다. 에러를 다루는 방법은 스위프트에서 4가지가 존재합니다.  각 접근 방식은 아래에 설명되어 있습니다. 에러가 던져졌을 때 프로그램에 흐름이 바뀝니다. 그러므로 에러를 발생시킬 수 있는 위치를 신속하게 식별하는 것이 중요합니다.

장소를 식별하기 위해서 함수 메소드 또는 이니셜라이저를 호출하는 코드 덩어리 전에 try 키워드를 사용합니다. (또는 try? , try!) 

 

Propagating Errors Using Throwing Functions

함수, 메소드. 이니셜라이저가 에러를 던질 수 있다는 것을 나타내기 위해 thorws 키워드를 함수 선언에 작성합니다.

thorws가 명시된 함수를 throwing function이라고 부릅니다.

func canThrowErrors() throws -> String

throwing function은 내부에 있는 에러를 호출되는 범위에 전파합니다. 일반 function은 에러를 전파할 수 없으며 내부에서 처리해야 합니다.

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 throws function 내부에서 실패할 경우를 guard 문으로 처리해 에러를 던져주는 모습입니다.

아래는 에러를 발생시킬 수 있는 vend함수를 사용한 경우 try를 통해 vend 함수를 실행한 곳까지 전파시켜주는 예시들입니다.

//다른 함수의 경우
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)
}

//이니셜라이저의 경우
struct PurchasedSnack {
    let name: String
    init(name: String, vendingMachine: VendingMachine) throws {
        try vendingMachine.vend(itemNamed: name)
        self.name = name
    }
}

 

Handling Errors Using Do-Catch

do-catch 를 사용하여 진행되고 있는 코드 블럭 내에서 에러를 다룰 수 있습니다. 만약 do절에서 에러가 던져진다면, catch절에서 에러를 다룰 수 있는 경우에 맞춰 실행합니다.(switch문과 유사)

 

만약 어떤 패턴도 매치되지 않는다면 이름이 error인 내부 상수에 저장합니다. (switchd의 default 생각하면 될듯)

var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8
do {
    try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
    print("Success! Yum.")
} catch VendingMachineError.invalidSelection {
    print("Invalid Selection.")
} catch VendingMachineError.outOfStock {
    print("Out of Stock.")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {
    print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
} catch {
    print("Unexpected error: \(error).")
}
// Prints "Insufficient funds. Please insert an additional 2 coins."

 

func nourish(with item: String) throws {
    do {
        try vendingMachine.vend(itemNamed: item)
    } catch is VendingMachineError { //is는 나중에 나올 타입캐스팅. 지금은 모든 에러를 다 걸러준다라고 생각하자
        print("Couldn't buy that from the vending machine.")
    }
}

do {
    try nourish(with: "Beet-Flavored Chips")
} catch {
    print("Unexpected non-vending-machine-related error: \(error)")
}
// Prints "Couldn't buy that from the vending machine."

살짝 이해하기 어려운 부분인데 이 예제의 위절과 아래절의 차이는 위절의 경우 nourish 함수가 에러를 처리하고 아래의 경우에는 nourish 함수가 호출된 곳에서 에러를 다룬다고 한다. 클로저의 영역에 따라 사용가능한 변수, 메소드가 다르니 이렇게 구분지은게 아닌가 싶다.

 

Converting Errors to Optional Values

try?를 통해 옵셔널 값으로 변경할 수 있다. 만약 에러가 발생하면 nil값을 반환한다. 모든 에러가 nil로 뭉퉁그려짐으로 에러 처리를 한가지로 사용하고 싶을 때 사용한다.

 

Disabling Error Propagation

에러가 일어나지 않을 거라고 알고있을 경우  try!를 사용하면 된다.

let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")

앱이 배포될 때 이미지가 포함되서 배포되기 때문에 실제 런타임에는 에러가 발생하지 않을 것을 알고 있기 때문에 try!를 사용했다.

 

Specifying Cleanup Actions

defer, open(:), close(:) 파일 및 자원 관련 내용. 나중에 다시 보기

'Swift Language Guide' 카테고리의 다른 글

Extensions  (0) 2020.11.24
타입 캐스팅 + 중첩 타입  (0) 2020.11.24
Optional Chaining(옵셔널 체이닝)  (0) 2020.11.18
11. 상속  (0) 2020.11.09
10. 서브스크립트  (0) 2020.11.08
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함