# デイニシャライゼーション(Deinitialization)

最終更新日: 2022/12/3\
原文: <https://docs.swift.org/swift-book/LanguageGuide/Deinitialization.html>

独自のクリーンアップが必要なリソースを解放する。

クラスのインスタンスが解放される直前に、\_デイニシャライザ\_が呼び出されます。`init` キーワードを使用してイニシャライザを作成する方法と同様に、`deinit` キーワードを使用してデイニシャライザを作成します。デイニシャライザは、クラス型でのみ使用できます。

## デイニシャライゼーションの仕組み(How Deinitialization Works)

Swift は、不要になったインスタンスのメモリへの割り当てを自動的に解除して、リソースを解放します。[Automatic Reference Counting(自動参照カウント)](https://swift-programming-language-jp.gitbook.io/the-swift-programming-language-jp/language-guide/automatic-reference-counting)で説明されているように、自動参照カウント(ARC)を通じてインスタンスのメモリを管理します。通常、インスタンスが解放されるときに手動でクリーンアップを実行する必要はありません。ただし、独自のリソースを取り扱っている場合は、追加のクリーンアップが必要になる場合があります。例えば、ファイルを開いてデータを書き込むカスタムクラスを作成する場合、クラスのインスタンスを解放する前にファイルを閉じる必要があります。

クラス定義は、クラスごとに 1 つのみのデイニシャライザを持つことができます。デイニシャライザはパラメータを取らず、丸括弧なしで記述されます:

```swift
deinit {
    // デイニシャライザの実行
}
```

インスタンスの解放が行われる直前に、デイニシャライザは自動的に呼び出されます。デイニシャライザを直接呼び出すことは許可されていません。スーパークラスのデイニシャライザは、そのサブクラスに継承され、サブクラスのデイニシャライザの実装の最後に自動的に呼び出されます。サブクラスが独自のデイニシャライザを提供しなくても、スーパークラスのデイニシャライザは常に呼び出されます。

インスタンスは、デイニシャライザが呼び出されるまで解放されないため、デイニシャライザは、呼び出されたインスタンスの全てのプロパティにアクセスでき、それらのプロパティに基づいて挙動を変更できます(閉じる必要があるファイルの名前を検索するなど)。

## デイニシャライザの挙動(Deinitializers in Action)

デイニシャライザの例を次に示します。この例では、シンプルなゲーム用に 2 つの新しいタイプ `Bank` と `Player` を定義しています。`Bank` クラスは、流通量が最大 10,000 の架空の通貨を管理します。ゲーム内に存在できる `Bank` は 1 つのみなので、`Bank` は現在の状態を保存および管理するための型プロパティと型メソッドを持つクラスとして実装されています:

```swift
class Bank {
    static var coinsInBank = 10_000
    static func distribute(coins numberOfCoinsRequested: Int) -> Int {
        let numberOfCoinsToVend = min(numberOfCoinsRequested, coinsInBank)
        coinsInBank -= numberOfCoinsToVend
        return numberOfCoinsToVend
    }
    static func receive(coins: Int) {
        coinsInBank += coins
    }
}
```

`Bank` は、`coinsInBank` プロパティを使用して、保有しているコインの現在の数を追跡します。また、コインの配布と受領を処理するために、`distribute(coins:)` と `receive(coins:)` という 2 つのメソッドも提供します。

`distribute(coins:)` メソッドは、配布する前に、銀行に十分なコインがあることを確認します。十分コインがない場合、`Bank` は要求された数よりも少ない数を返します(銀行にコインが残っていない場合はゼロを返します)。`Bank` は整数値を返すことで、実際に配布されたコイン数を示します。

`receive(coins:)` メソッドは、受け取った数のコインを `Bank` のコインストアに追加するだけです。

`Player` クラスは、ゲーム内のプレイヤーを表します。各プレイヤーは、常に一定数のコインを財布に保管しています。これは、プレイヤーの `coinsInPurse` プロパティによって表されます:

```swift
class Player {
    var coinsInPurse: Int
    init(coins: Int) {
        coinsInPurse = Bank.distribute(coins: coins)
    }
    func win(coins: Int) {
        coinsInPurse += Bank.distribute(coins: coins)
    }
    deinit {
        Bank.receive(coins: coinsInPurse)
    }
}
```

各 `Player` インスタンスは、銀行から指定数のコインを受け取って初期化されますが、銀行に指定された数のコインがない場合、`Player` インスタンスはその数よりも少ないコインを受け取る場合があります。

`Player` クラスは `win(coins:)` メソッドを定義し、銀行から一定数のコインを取得してプレイヤーの財布に追加します。`Player` クラスは、`Player` インスタンスの解放直前に呼び出されるデイニシャライザも実装します。ここで、デイニシャライザは単純にプレイヤーのすべてのコインを銀行に返します。

```swift
var playerOne: Player? = Player(coins: 100)
print("新しいプレイヤーが \(playerOne!.coinsInPurse) コイン受け取りゲームに参加しました")
// 新しいプレイヤーが 100 コイン受け取りゲームに参加しました
print("現在、銀行には \(Bank.coinsInBank) コインが残っています")
// 現在、銀行には 9900 コインが残っています
```

新しい `Player` インスタンスは、可能ならば 100 コインを受け取って作成されています。この `Player` インスタンスは、`playerOne` というオプショナルの `Player` 変数に保存されます。プレイヤーはいつでもゲームを終了できるため、ここではオプショナルの変数が使用されます。オプショナルを使用すると、現在ゲームにプレイヤーがいるかどうかを追跡できます。

`playerOne` はオプショナルのため、デフォルトのコイン数を出力するためにその `coinsInPurse` プロパティにアクセスするとき、および `win(coins:)` メソッドが呼び出されるときはいつでも、感嘆符 (!) を付けています:

```swift
playerOne!.win(coins: 2_000)
print("PlayerOne は 2000 コインを獲得しました。そして現在 \(playerOne!.coinsInPurse) コインを持っています")
// PlayerOne は 2000 コインを獲得しました。そして現在 2100 コインを持っています
print("現在、銀行には \(Bank.coinsInBank) コインしか残っていません")
// 現在銀行には 7900 コインしか残っていません
```

ここで、プレイヤーは 2,000 コインを獲得しました。プレイヤーの財布には 2,100 枚のコインがあり、銀行には 7,900 枚のコインしか残っていません。

```swift
playerOne = nil
print("PlayerOne はゲームから離れました")
// PlayerOne はゲームから離れました
print("現在、銀行には \(Bank.coinsInBank) コインがあります")
// 現在、銀行には 10000 コインがあります
```

プレイヤーはゲームから離れました。これは、オプショナルの `playerOne` 変数を `nil` に設定することで示しています。つまり「`Player` インスタンスがない」ことを意味します。この時点で、`playerOne` 変数の `Player` インスタンスへの参照が解放されています。他のプロパティや変数が `Player` インスタンスを参照していないため、メモリから解放されます。解放される直前に、デイニシャライザが自動的に呼び出され、コインが銀行に戻されています。
