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

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.

主站蜘蛛池模板: 彭泽县| 晋江市| 江源县| 阿瓦提县| 花莲县| 亳州市| 南皮县| 杭锦旗| 柯坪县| 黄大仙区| 汉寿县| 定安县| 沅江市| 偏关县| 曲麻莱县| 广河县| 眉山市| 开原市| 灵璧县| 临沂市| 遂溪县| 枣阳市| 宝丰县| 通许县| 西平县| 南乐县| 锡林郭勒盟| 新沂市| 鄂尔多斯市| 镇赉县| 留坝县| 仪征市| 潞城市| 白城市| 镇雄县| 诏安县| 黄大仙区| 昭通市| 丽水市| 乌什县| 太和县|