在釋放類(lèi)實(shí)例之前立即調(diào)用反初始化器。
使用deinit關(guān)鍵字編寫(xiě)反初始化器,類(lèi)似于使用init關(guān)鍵字編寫(xiě)初始化器。
反初始化器只對(duì)class 類(lèi)型可用。
How Deinitialization Works Deinitialization是如何工作的
當(dāng)不再需要實(shí)例時(shí),Swift會(huì)自動(dòng)釋放它們,以釋放資源。Swift通過(guò)自動(dòng)引用計(jì)數(shù)(ARC)處理實(shí)例的內(nèi)存管理,如自動(dòng)引用計(jì)數(shù)中所述。通常,在釋放實(shí)例時(shí)不需要執(zhí)行手動(dòng)清理。然而,當(dāng)您使用自己的資源時(shí),您可能需要自己執(zhí)行一些額外的清理。例如,如果您創(chuàng)建一個(gè)自定義類(lèi)來(lái)打開(kāi)一個(gè)文件并向其寫(xiě)入一些數(shù)據(jù),您可能需要在釋放類(lèi)實(shí)例之前關(guān)閉該文件。
類(lèi)定義每個(gè)類(lèi)最多可以有一個(gè)反初始化器。反初始化器不接受任何參數(shù),并且沒(méi)有括號(hào):
deinit {
// perform the deinitialization
}
在實(shí)例釋放位置發(fā)生之前,會(huì)自動(dòng)調(diào)用反初始化器。不允許您自己調(diào)用反初始化器。超類(lèi)初始化器由子類(lèi)繼承,超類(lèi)初始化器在子類(lèi)初始化器實(shí)現(xiàn)結(jié)束時(shí)自動(dòng)調(diào)用。總是調(diào)用超類(lèi)的反初始化器,即使子類(lèi)沒(méi)有提供自己的反初始化器。
因?yàn)橐粋€(gè)實(shí)例直到它的反初始化器被調(diào)用后才被釋放,所以反初始化器可以訪問(wèn)它所調(diào)用的實(shí)例的所有屬性,并可以根據(jù)這些屬性修改它的行為(例如查找需要關(guān)閉的文件的名稱(chēng))。
Deinitializers in Action 反初始化運(yùn)轉(zhuǎn)
下面是一個(gè)正在運(yùn)行的反初始化器示例。這個(gè)例子為一個(gè)簡(jiǎn)單的游戲定義了兩種新類(lèi)型,Bank和Player。銀行類(lèi)管理著一種虛構(gòu)的貨幣,這種貨幣的流通數(shù)量不可能超過(guò)1萬(wàn)枚。游戲中只能有一個(gè)銀行,所以銀行被實(shí)現(xiàn)為一個(gè)類(lèi),帶有類(lèi)型屬性和方法來(lái)存儲(chǔ)和管理它的當(dāng)前狀態(tài):
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
}
}
銀行會(huì)記錄它持有的硬幣的數(shù)量。它還提供了兩種方法——distribute(coins:) 和 receive(coins:)來(lái)處理硬幣的分發(fā)和收集。
distribute(coins:) 方法在分發(fā)前檢查銀行中是否有足夠的硬幣。如果沒(méi)有足夠的硬幣,銀行返回的數(shù)字將小于請(qǐng)求的數(shù)字(如果銀行中沒(méi)有硬幣,則返回零)。它返回一個(gè)整數(shù)值,以指示所提供的硬幣的實(shí)際數(shù)量。
receive(coins:)方法簡(jiǎn)單地將接收到的硬幣數(shù)量添加回銀行的硬幣存儲(chǔ)中。
Player類(lèi)描述游戲中的一個(gè)玩家。每個(gè)玩家的錢(qián)包里隨時(shí)都有一定數(shù)量的硬幣。這由玩家的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)
}
}
在初始化過(guò)程中,每個(gè)玩家實(shí)例都使用指定數(shù)量的銀行硬幣初始化,盡管如果沒(méi)有足夠的硬幣可用,玩家實(shí)例收到的硬幣可能少于該數(shù)量。
Player類(lèi)定義了win(coins:)方法,該方法從銀行獲取一定數(shù)量的硬幣并將其添加到玩家的錢(qián)包中。Player類(lèi)還實(shí)現(xiàn)了一個(gè)反初始化器,它在釋放Player實(shí)例之前被調(diào)用。在這里,deinitializer簡(jiǎn)單地將玩家的所有硬幣返回給銀行:
var playerOne: Player? = Player(coins: 100)
print("A new player has joined the game with \(playerOne!.coinsInPurse) coins")
// Prints "A new player has joined the game with 100 coins"
print("There are now \(Bank.coinsInBank) coins left in the bank")
// Prints "There are now 9900 coins left in the bank"
創(chuàng)建一個(gè)新的Player實(shí)例,如果有100個(gè)硬幣可用,則請(qǐng)求100個(gè)硬幣。此玩家實(shí)例存儲(chǔ)在名為playerOne的可選播放器變量中。這里使用了一個(gè)可選變量,因?yàn)橥婕铱梢噪S時(shí)離開(kāi)游戲。可選選項(xiàng)允許您跟蹤當(dāng)前是否有玩家在游戲中。
因?yàn)閜layerOne是可選的,所以當(dāng)訪問(wèn)它的coinsInPurse屬性來(lái)打印它的默認(rèn)硬幣數(shù)量時(shí),以及當(dāng)調(diào)用它的win(coins:)方法時(shí),用感嘆號(hào)(!)限定它:
playerOne !贏得(硬幣:2 _000)
打印(“PlayerOne贏得2000枚硬幣,現(xiàn)在有\(zhòng)(PlayerOne !.coinsInPurse)硬幣”)
//打印“PlayerOne贏得2000枚硬幣,現(xiàn)在擁有2100枚硬幣”
打印(“銀行現(xiàn)在只剩下\(bank . coinsinbank)硬幣了”)
//打印“銀行現(xiàn)在只剩下7900枚硬幣了”
在這里,玩家贏得了2000枚硬幣。現(xiàn)在玩家的錢(qián)包里有2100枚硬幣,而銀行只剩下7900枚硬幣。
playerOne = nil
print("PlayerOne has left the game")
// Prints "PlayerOne has left the game"
print("The bank now has \(Bank.coinsInBank) coins")
// Prints "The bank now has 10000 coins"
玩家現(xiàn)在已經(jīng)離開(kāi)游戲。這是通過(guò)將可選的playerOne變量設(shè)置為nil來(lái)表示的,這意味著“沒(méi)有玩家實(shí)例”。在這種情況發(fā)生時(shí),playerOne變量對(duì)Player實(shí)例的引用被破壞。沒(méi)有其他屬性或變量仍然引用Player實(shí)例,因此釋放它是為了釋放它的內(nèi)存。就在這之前,它的反初始化器被自動(dòng)調(diào)用,它的硬幣被返回給銀行。