デイニシャライゼーション
カスタムクリーンアップが必要なリソースを解放します。
デイニシャライザは、クラスインスタンスが解放される直前に呼び出されます。デイニシャライザは、init
キーワードで初期化子を書くのと同様に、deinit
キーワードで書きます。デイニシャライザはクラス型でのみ利用可能です。
デイニシャライゼーションの仕組み
Swiftは、インスタンスが不要になったときに自動的に解放してリソースを解放します。Swiftは、自動参照カウント(ARC)を通じてインスタンスのメモリ管理を行います。詳細は自動参照カウントを参照してください。通常、インスタンスが解放されるときに手動でクリーンアップを行う必要はありません。しかし、自分のリソースを扱う場合は、追加のクリーンアップが必要になることがあります。例えば、ファイルを開いてデータを書き込むカスタムクラスを作成した場合、クラスインスタンスが解放される前にファイルを閉じる必要があるかもしれません。
クラス定義には、クラスごとに最大1つのデイニシャライザを持つことができます。デイニシャライザはパラメータを取らず、括弧なしで書かれます:
deinit {
// デイニシャライゼーションを実行
}
デイニシャライザは自動的に呼び出され、インスタンスの解放が行われる直前に実行されます。デイニシャライザを自分で呼び出すことはできません。スーパークラスのデイニシャライザはサブクラスに継承され、サブクラスのデイニシャライザの実装の最後に自動的に呼び出されます。サブクラスが独自のデイニシャライザを提供しない場合でも、スーパークラスのデイニシャライザは常に呼び出されます。
インスタンスはデイニシャライザが呼び出された後に解放されるため、デイニシャライザは呼び出されたインスタンスのすべてのプロパティにアクセスでき、それらのプロパティに基づいて動作を変更することができます(例えば、閉じる必要があるファイルの名前を調べるなど)。
デイニシャライザの実例
ここにデイニシャライザの実例があります。この例では、簡単なゲームのためにBank
とPlayer
という2つの新しい型を定義します。Bank
クラスは、流通するコインが10,000枚を超えないように管理します。ゲーム内には常に1つの銀行しか存在せず、銀行はその現在の状態を保存および管理するための型プロパティとメソッドを持つクラスとして実装されています:
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
プロパティで現在保持しているコインの数を追跡します。また、コインの配布と回収を処理するための2つのメソッド、distribute(coins:)
とreceive(coins:)
を提供します。
distribute(coins:)
メソッドは、コインを配布する前に銀行に十分なコインがあるかどうかを確認します。コインが足りない場合、Bankは要求された数よりも少ない数のコインを返します(銀行にコインが残っていない場合はゼロを返します)。このメソッドは、実際に提供されたコインの数を示す整数値を返します。
receive(coins:)
メソッドは、受け取ったコインの数を銀行のコインストアに追加するだけです。
Player
クラスは、ゲーム内のプレイヤーを表します。各プレイヤーは、任意の時点で財布に一定数のコインを持っています。これはプレイヤーのcoinsInPurse
プロパティで表されます:
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
クラスは、銀行から一定数のコインを取得してプレイヤーの財布に追加するwin(coins:)
メソッドを定義しています。また、Player
クラスはデイニシャライザを実装しており、Player
インスタンスが解放される直前に呼び出されます。ここでは、デイニシャライザはプレイヤーのすべてのコインを銀行に返すだけです:
var playerOne: Player? = Player(coins: 100)
print("新しいプレイヤーがゲームに参加し、\(playerOne!.coinsInPurse)コインを持っています")
// "新しいプレイヤーがゲームに参加し、100コインを持っています"と表示されます
print("銀行には現在\(Bank.coinsInBank)コインが残っています")
// "銀行には現在9900コインが残っています"と表示されます
新しいPlayer
インスタンスが作成され、利用可能であれば100コインを要求します。このPlayer
インスタンスは、playerOne
というオプショナルなPlayer
変数に格納されます。ここでは、プレイヤーがいつでもゲームを離れることができるため、オプショナル変数が使用されています。オプショナルを使用することで、現在ゲームにプレイヤーがいるかどうかを追跡できます。
playerOne
はオプショナルなので、そのcoinsInPurse
プロパティにアクセスしてデフォルトのコイン数を表示する場合や、win(coins:)
メソッドを呼び出す場合には感嘆符(!
)を付けて使用します:
playerOne!.win(coins: 2_000)
print("PlayerOneは2000コインを獲得し、現在\(playerOne!.coinsInPurse)コインを持っています")
// "PlayerOneは2000コインを獲得し、現在2100コインを持っています"と表示されます
print("銀行には現在\(Bank.coinsInBank)コインしか残っていません")
// "銀行には現在7900コインしか残っていません"と表示されます
ここで、プレイヤーは2000コインを獲得しました。プレイヤーの財布には現在2100コインがあり、銀行には7900コインしか残っていません。
playerOne = nil
print("PlayerOneはゲームを離れました")
// "PlayerOneはゲームを離れました"と表示されます
print("銀行には現在\(Bank.coinsInBank)コインがあります")
// "銀行には現在10000コインがあります"と表示されます
プレイヤーはゲームを離れました。これは、オプショナルなplayerOne
変数をnil
に設定することで示されます。これは「Playerインスタンスが存在しない」という意味です。この時点で、playerOne
変数のPlayer
インスタンスへの参照が切れます。他のプロパティや変数がPlayer
インスタンスを参照していないため、メモリを解放するためにインスタンスが解放されます。この直前に、デイニシャライザが自動的に呼び出され、プレイヤーのコインが銀行に返されます。