The Swift tutorial and the like

  • 2020-05-12 06:16:42
  • OfStack

The destructor is called before an instance of the class is released. The destructor is defined with the keyword deinit, similar to the initialization function defined with init. Destructors apply only to class types.

1. Principle of destructing process

Swift automatically frees up instances that are no longer needed to free up resources. As described in chapter 1 of automatic reference counting, Swift handles the memory management of instances through automatic reference counting (ARC). Usually when your instance is released you don't need to clean it up manually. However, you may need to do some extra cleanup when using your own resources. For example, if you create a custom class to open a file and write some data, you may need to close the file before the class instance is released.

In the definition of a class, each class can have at most one destructor. The destructor takes no arguments and is written without parentheses:


deinit {
// Perform the destructor procedure
}

The destructor is called automatically 1 step before the instance release occurs. You are not allowed to actively call your own destructor. The subclass inherits the destructor of the parent class, and at the end of the subclass destructor implementation, the destructor of the parent class is automatically called. The destructor of the parent class is always called, even if the subclass does not provide its own destructor.

Because the instance is not released until its destructor is called, the destructor can access all the properties of the requested instance and modify its behavior based on those properties (such as looking for the name of a file that needs to be closed).

2. Destructor operation

Here is an example of a destructor operation. This example is a simple game that defines two new types, Bank and Player. The Bank structure manages the circulation of one virtual currency in which Bank can never have more than 10,000 COINS. One and only one Bank exists in this game, so Bank is implemented by a structure with static properties and static methods to store and manage its current state.


struct Bank {
static var coinsInBank = 10_000
static func vendCoins(var numberOfCoinsToVend: Int) -> Int {
numberOfCoinsToVend = min(numberOfCoinsToVend, coinsInBank)
coinsInBank -= numberOfCoinsToVend
return numberOfCoinsToVend
}
static func receiveCoins(coins: Int) {
coinsInBank += coins
}
}

Bank tracks the current number of COINS it owns based on its coinsInBank property. The bank also provides two methods -- vendCoins and receiveCoins -- to handle coin distribution and collection.

The vendCoins method checks if there are enough COINS before bank hands them out. If there are not enough COINS, Bank returns a number smaller than the number requested (0 if there are no COINS left in bank). The vendCoins method declares numberOfCoinsToVend as a variable parameter, which allows you to change the number inside the body of the method without having to define a new variable. The vendCoins method returns an integer value indicating the actual number of COINS provided.

The receiveCoins method simply adds up bank's coin store and the number of COINS received, and then saves it back to bank.

The Player class describes a player in the game. Each player has a fixed number of COINS stored in their wallet at any given time. This is reflected by the coinsInPurse attribute of player:


class Player {
var coinsInPurse: Int
init(coins: Int) {
coinsInPurse = Bank.vendCoins(coins)
}
func winCoins(coins: Int) {
coinsInPurse += Bank.vendCoins(coins)
}
deinit {
Bank.receiveCoins(coinsInPurse)
}
}

Each instance of Player is initialized by a starting quota of 1 specified number of COINS, which are obtained during the initialization of bank. If not enough COINS are available, the Player instance may receive fewer COINS than the specified number.

The Player class defines an winCoins method that takes a fixed number of COINS from the bank and adds them to the player's wallet. The Player class also implements a destructor that is called one step before the Player instance is released. Here the destructor simply returns all of the player's COINS to the bank:


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

A new Player instance is created with a request for 1 100 COINS (if any). This Player instance is stored in an optional Player variable called playerOne. An optional variable is used because the player can leave the game at any time. Setting to optional allows you to keep track of whether or not a player is currently in the game.

Since playerOne is optional, it is marked by an exclamation point (!). Each time its winCoins method is called, the coinsInPurse property is accessed and printed out its default number of COINS.


playerOne!.winCoins(2_000)
println( " PlayerOne won 2000 coins & now has \    (playerOne!.coinsInPurse) coins " )
// The output " PlayerOne won 2000 coins & now has 2100 coins "
println( " The bank now only has (Bank.coinsInBank) coins left " )
// The output " The bank now only has 7900 coins left "

Here, player has won 2,000 COINS. While the player wallet now has 2,100 COINS, the bank has only 7,900 COINS left.


playerOne = nil
println( " PlayerOne has left the game " )
// The output " PlayerOne has left the game "
println( " The bank now has (Bank.coinsInBank) coins " )
// The output " The bank now has 10000 coins "

The player has now left the game. This indicates that the optional playerOne variable is to be set to nil, which means "there are no instances of Player". When this happens, the reference of the playerOne variable to the Player instance is broken. No other property or variable references the Player instance, so it is freed in order to clear the memory it occupies. Step 1 before this happens, its destructor is automatically called and its coin is returned to the bank.


Related articles: