官术网_书友最值得收藏!

Throwing and catching errors

Swift has an error handling mechanism that is based on throwing and catching errors, very similar to JavaScript or Java. In Swift, Error is simply a protocol. Any of your custom types conforming to the Error protocol can be used, and can also be thrown. This provides us with the ability to be as expressive as possible with the underlying types that we'll be using.

Unlike in Java, for example, it is not possible to specialize error catching, but you can always leverage pattern matching to determine the kind of error that's been thrown. You may want to define functions that throw, in order to indicate that an abnormal operation has run, and therefore, the execution of the program should properly handle these abnormal operations.

Let's look at our credit card example and suppose that we can create charges on a prepaid card:

class CreditCard {
private(set) var balance: Int // balance is in cents

init(balance: Int) {
self.balance = balance
}

func charge(amount: Int) {
balance -= amount
}
}

let card = CreditCard(balance: 10000)
card.charge(amount: 2000)
card.balance == 8000

This implementation is now completely unsafe, due to the following:

  • A developer can increment the balance by providing a negative amount
  • The balance can become negative, and we may want to include restrictions

We could use UInt instead of Int, but, for the sake of the example, we'll write our own error handling logic.

Let's rewrite our example, as follows:

class CreditCard {

Let's define ChargeError as an enum, which encompasses the two expected errors. Using an enum lets you safely define a finite possibility of values, while ensuring that the consumer will always implement all of the cases, and therefore, handle all of the error types:

    enum ChargeError: Error {
case invalidAmount
case insufficientFunds
}

/* unchanged implementation of init / balance */

We can now mark our charge method with the throws keyword, to indicate to anyone using this method that it can fail:

    func charge(amount: Int) throws {
guard amount >= 0 else { throw ChargeError.invalidAmount }
guard balance >= amount else { throw ChargeError.insufficientFunds }
balance -= amount
}
}

Let's take a look at how to use this API now:

The first way is to use the do...catch pattern and cast the error as the one thrown, as follows:

let card = CreditCard(balance: 10000)
do {
try card.charge(amount: 2000)
} catch CreditCard.ChargeError.invalidAmount {
/* handle invalidAmount */
} catch CreditCard.ChargeError.insufficientFunds {
/* handle insufficientFunds */
} catch {}

If you're not interested in catching errors, you can also use try?:

try? card.charge(amount: -1000) // this will fail safely and nicely

Error handling is a fundamental feature in Swift, when you need to interact with failable code. Throughout the course of this book, you'll see other patterns that encapsulate error management differently, and which many Swift users prefer over the default do...catch...throw pattern. However, for now let's continue our exploration of the Standard Library with the different container types.

主站蜘蛛池模板: 平顶山市| 贺兰县| 浦东新区| 黑山县| 卓尼县| 昌都县| 辽宁省| 丹寨县| 舞阳县| 华池县| 靖江市| 新竹市| 莱阳市| 台安县| 临夏市| 汕头市| 黄山市| 丹棱县| 获嘉县| 长武县| 大石桥市| 平乐县| 岐山县| 莎车县| 太和县| 额尔古纳市| 邯郸县| 建始县| 天台县| 敦化市| 库伦旗| 元氏县| 灵台县| 桐庐县| 张家界市| 本溪市| 扬中市| 达孜县| 临猗县| 荆门市| 乐昌市|