天天看點

Swift程式設計十六(Deinitialization)Deinitialization

案例代碼下載下傳

Deinitialization

一個類的執行個體被釋放之前立即調用deinitializer。使用deinit關鍵字編寫deinitializers ,類似于使用init關鍵字編寫初始化程式的方式。Deinitializers僅适用于類類型。

Deinitialization如何運作

當不再需要執行個體時,Swift會自動釋放執行個體,以釋放資源。Swift通過處理執行個體通過自動引用計數(ARC)管理記憶體,如在自動引用計數中描述。通常,在取消配置設定執行個體時,無需執行手動清理。但是,當使用自己的資源時,可能需要自己執行一些額外的清理。例如,如果建立自定義類以打開檔案并向其寫入一些資料,則可能需要在執行個體銷毀之前關閉該檔案。

類定義每個類最多可以有一個deinitializer。deinitializer不接受任何參數,并且沒有括号寫入:

deinit {
    // 執行deinitialization
}
           

在執行個體銷毀之前,會自動調用deinitialization。不能自己調用deinitializer。超類deinitializers由其子類繼承,超類deinitializer在子類deinitializer實作的末尾自動調用。即使子類不提供自己的deinitializer,也始終調用超類deinitializers。

因為執行個體在調用deinitializer之後才被釋放,是以deinitializer可以通路調用它的執行個體的所有屬性,并可以根據這些屬性修改其行為(例如查找需要關閉的檔案的名稱) )。

Deinitializers in Action

這是一個Deinitializers的例子。這個例子定義了兩種新類型,Bank和Player,對于一個簡單的遊戲。該Bank類管理一種虛拟貨币,其流通量永遠不會超過10000。Bank遊戲中隻能有一個,是以Bank被實作為具有類型屬性和方法的類來存儲和管理其目前狀态:

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:)處理硬币的配置設定和收集。

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如果沒有足夠的硬币可用,則執行個體可以接收少于該數量的執行個體。

Player類定義了一個win(coins:)方法,它從銀行擷取一定數量硬币,并将它們添加到玩家的錢包。Player類還實作了deinitializer,這在Player執行個體被釋放前調用。在這裡,deinitializer隻是将所有玩家的硬币歸還給銀行:

var playerOne: Player? = Player(coins: 100)
print("A new player has joined the game with \(playerOne!.coinsInPurse) coins")
print("There are now \(Bank.coinsInBank) coins left in the bank")
           

Player建立一個新執行個體,如果可用則請求100個硬币。此Player執行個體存儲在名為playerOne的Player可選變量中。這裡使用可選變量,因為玩家可以随時離開遊戲。可選項可跟蹤遊戲中目前是否有玩家。

因為playerOne它是可選的,當通路其coinsInPurse屬性以列印其預設硬币數時,調用win(coins:)方法時,都會被感歎号(!)限定:

playerOne!.win(coins: 2_000)
print("PlayerOne won 2000 coins & now has \(playerOne!.coinsInPurse) coins")
print("The bank now only has \(Bank.coinsInBank) coins left")
           

在這裡,玩家赢得了2,000個硬币。玩家的錢包現在包含2,100個硬币,銀行隻剩下7,900個硬币。

playerOne = nil
print("PlayerOne has left the game")
print("The bank now has \(Bank.coinsInBank) coins")
           

玩家現在已離開遊戲。通過将可選playerOne變量設定為nil表示“無Player執行個體” 來訓示。在發生這種情況時,playerOne變量對Player執行個體的引用被破壞。沒有其他屬性或變量仍然引用該Player執行個體,是以它被釋放以釋放其記憶體。就在這種情況發生之前,它的自動調節器會自動調用,并将其硬币返還給銀行。