Swift 5.x - 析構函數(中文文檔)

引言

繼續學習Swift文檔,從上一章節:初始化,咱們學習了Swift初始化相關的內容,如類、結構體和枚舉初始化方法的定義和使用、 convenience 關鍵詞定義便捷初始化方法、初始化失敗語法 init? 和強制解包 init!required關鍵詞修飾init方法、用閉包和函數設置屬性默認值等這些內容。如今,咱們學習Swift的析構函數相關的內容。因爲篇幅較長,這裏分篇來記錄,接下來,Fighting!html

題外話:Deinitialization這個翻譯過來是「反初始化」,感受不是很對,特地去搜索一下相關內容,最後以爲「析構函數」會更適合一點,因此這裏就用這個翻譯結果爲準吧。若是有誤,歡迎指正哈^.^!swift

若是你已經掌握了這個,跳轉下一章節:可選連接bash

析構函數

在取消釋放類實例以前,將調用析構函數。 您使用deinit關鍵字編寫析構函數,相似於使用init關鍵字編寫初始化方法的方式。 析構函數僅在類類型上可用。閉包

1 析構函數是如何工做的?

當再也不須要實例時,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實例,所以將其釋放以釋放其內存。 在此以前,它的析構函數會自動被調用,而且其硬幣會退還至銀行。

上一章節:初始化

下一章節:可選連接

參考文檔:Swift - Deinitialization

相關文章
相關標籤/搜索