Posted at

Swift エラーハンドリングの基本


この記事は何?

Swiftプログラミングでのエラー処理について、調べました。

忘備録を兼ねて投稿します。

参考記事: Swift Language Guide


実行環境

Swift5.x

Xcode11 beta2

macOS 10.14 Mojave


ハンズオン

エラーを定義して、スローするプログラムを記述します。


こんなクラスがあったとして

自動販売機をコードで表現しています。


自動販売機のクラス

// 商品の金額と残り個数

struct ItemInfo {
var price: Int
var count: Int
}

// 自動販売機
class VendingMachine {
var inventories = [String: ItemInfo]() // 在庫の商品
var coinsDeposited = 0 // 預かり金

// 商品を販売
func vend(itemNamed name: String) {
let selectedItem = inventories[name]
coinsDeposited -= selectedItem.price

var newItem = selectedItem
newItem.count -= 1
inventories[name] = newItem // updating a value

print("Dispensing \(name)")
}
}



自販機のインスタンス

自動販売機のインスタンス drinkStand を生成して、"Coke" を買います。


自販機インスタンスを生成する

let drinkStand = VendingMachine()

// ドリンクを補填
drinkStand.inventories = [
"Coke" : ItemInfo(price: 120, count: 7),
"Soda" : ItemInfo(price: 80, count: 3),
"Milk" : ItemInfo(price: 100, count: 10)]

// コーラを買う
drinkStand.vend(itemNamed: "Coke")



起こりうるエラー

この自販機プログラムでは、以下のようなエラーが発生するかもしれません。


  • 無効な商品を選択

  • 支払額が不足

  • 在庫なし

自販機で起こりうるエラー を列挙型を使って、コードで定義します。

このとき、Error プロトコルに準拠させておくと、Swiftが自動的にエラーハンドリングの対象にしてくれます。


エラーの定義

enum VendingMachineError: Error {

case invalidSelection // 無効な選択
case insufficientFunds(coinsNeeded: Int) // 支払額が不足
case outOfStock // 在庫なし
}


Error プロトコル

具体的な実装はなく、カラのプロトコルです。

準拠に適合するために、何か特別なことをする必要はありません。


エラーをthrow(スロー)する

自販機クラス内のエラーが発生しそうな行で、エラーをスロー します。

throw キーワードを使います。

どんなエラーが発生したかは、VendingMachineError 型を使って指定できます。

この時点で、vend(itemNamed:) メソッドはエラーを throw するかもしれないメソッドになりました。

メソッド宣言のパラメータ直後に throws キーワードを記述します。


エラーをスローする

class VendingMachine {

var inventories = [String: ItemInfo]()
var coinsDeposited = 0

func vend(itemNamed name: String) throws {
// 無効な商品を選択したら、エラーをスローする
guard let selectedItem = inventories[name] else {
throw VendingMachineError.invalidSelection
}
coinsDeposited -= selectedItem.price

var newItem = selectedItem
newItem.count -= 1
inventories[name] = newItem

print("Dispensing \(name)")
}
}



エラーをスローする関数の定義

throw キーワードと throws キーワードは間違いやすいので、気をつける必要があります。


スロー関数の宣言(例)

// エラーをスローできる関数の宣言 

func canThrowErrorsMethod() throws -> <ReturnType>

// エラーをスローしない関数の宣言
func cannotThrowErrorsMethod() -> <ReturnType>