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

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.

主站蜘蛛池模板: 青海省| 肇东市| 津南区| 昌吉市| 苏州市| 临沂市| 梅河口市| 南溪县| 长白| 健康| 科技| 麻阳| 岑溪市| 庆元县| 保德县| 万荣县| 绵竹市| 天柱县| 揭西县| 三明市| 白城市| 乐陵市| 葵青区| 古蔺县| 阿合奇县| 金塔县| 闸北区| 保亭| 乾安县| 广水市| 邢台县| 深圳市| 雷山县| 闻喜县| 宁德市| 策勒县| 剑川县| 睢宁县| 陈巴尔虎旗| 兴和县| 奉贤区|