繼續學習Swift文檔,從上一章節:初始化,咱們學習了Swift初始化相關的內容,如類、結構體和枚舉初始化方法的定義和使用、 convenience 關鍵詞定義便捷初始化方法、初始化失敗語法 init? 和強制解包 init!、 required關鍵詞修飾init方法、用閉包和函數設置屬性默認值等這些內容。如今,咱們學習Swift的析構函數相關的內容。因爲篇幅較長,這裏分篇來記錄,接下來,Fighting!html
題外話:Deinitialization這個翻譯過來是「反初始化」,感受不是很對,特地去搜索一下相關內容,最後以爲「析構函數」會更適合一點,因此這裏就用這個翻譯結果爲準吧。若是有誤,歡迎指正哈^.^!swift
若是你已經掌握了這個,跳轉下一章節:可選連接bash
在取消釋放類實例以前,將調用析構函數。 您使用deinit關鍵字編寫析構函數,相似於使用init關鍵字編寫初始化方法的方式。 析構函數僅在類類型上可用。閉包
當再也不須要實例時,Swift會自動釋放其實例,以釋放資源。 Swift經過自動引用計數(ARC)處理實例的內存管理,如自動引用計數中所述。 一般,在釋放實例後,您無需執行手動清理。 可是,當您使用本身的資源時,可能須要本身執行一些額外的清理。 例如,若是建立一個自定義類來打開文件並向其中寫入一些數據,則可能須要在釋放該類實例以前關閉該文件。ide
每一個類定義最多能夠有一個析構函數。 析構函數不接受任何參數,而且寫成無括號:函數
deinit {
// perform the deinitialization
}
複製代碼
在實例解除分配發生以前,會自動調用析構函數。 您不容許本身調用析構函數。 父類析構函數由其子類繼承,而且父類析構函數在子類析構函數實現的末尾自動調用。 即便子類沒有提供本身的析構函數,也老是會調用父類析構函數。post
因爲實例在調用其取消初始化以後才被釋放,所以析構函數能夠訪問其被調用實例的全部屬性,並能夠基於這些屬性修改其行爲(例如查找須要關閉的文件名) )。學習
這是一個實施析構函數的示例。 本示例爲一個簡單的遊戲定義了兩種新類型,即Bank和Player。 銀行類管理一種虛構貨幣,流通中的硬幣永遠不能超過10,000個。 遊戲中只能有一個Bank,所以Bank被實現爲具備類型屬性和存儲和管理其當前狀態的方法的類:ui
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
}
}
複製代碼
銀行使用coinsInBank屬性跟蹤當前持有的硬幣數量。 它還提供了兩種方法(distribute(coins:) 和receive(coins:))來處理硬幣的分發和收集。spa
distribute(coins:) 方法在分發以前檢查銀行中是否有足夠的硬幣。 若是沒有足夠的硬幣,則Bank返回的數字小於所請求的數字(若是銀行中沒有剩餘硬幣,則返回零)。它返回一個整數值以指示所提供的硬幣的實際數量。
receive(coins:)方法只是將接收到的硬幣數量加回到銀行的硬幣商店中。Player類描述遊戲中的玩家。
每一個玩家隨時均可以在錢包中存放必定數量的硬幣。 這由玩家的coinInPurse屬性表示:
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實例被釋放以前被調用。 在這裏,析構函數只需將玩家的全部硬幣返回銀行:
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"
複製代碼
建立一個新的Player實例,並請求100個硬幣(若是有)。 此Player實例存儲在一個名爲playerOne的可選Player變量中。 這裏使用一個可選變量,由於玩家能夠隨時離開遊戲。 可選功能可以讓您跟蹤遊戲中當前是否有玩家。
由於playerOne是可選的,因此當訪問其instancesInPurse屬性以打印其默認代幣數量,而且每當調用其win(coins :)方法時,它都帶有一個感嘆號(!)。
playerOne!.win(coins: 2_000)
print("PlayerOne won 2000 coins & now has \(playerOne!.coinsInPurse) coins")
// Prints "PlayerOne won 2000 coins & now has 2100 coins"
print("The bank now only has \(Bank.coinsInBank) coins left")
// Prints "The bank now only has 7900 coins left"
複製代碼
在這裏,玩家贏得了2,000個硬幣。 如今,玩家的錢包包含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"
複製代碼
玩家如今已經離開了遊戲。 這是經過將可選的playerOne變量設置爲nil來表示的,表示「無Player實例」。 發生這種狀況時,playerOne變量對Player實例的引用已損壞。 沒有其餘屬性或變量仍在引用Player實例,所以將其釋放以釋放其內存。 在此以前,它的析構函數會自動被調用,而且其硬幣會退還至銀行。