A deinitializer is called immediately before a class instance is deallocated. You write deinitializers with the deinit keyword, similar to how initializers are written with the init keyword. Deinitializers are only available on class types.
析构方法在一个类实例被撤销分配之前调用。析构方法用deinit关键字标示。析构方法只能用于类类型。
Swift automatically deallocates your instances when they are no longer needed, to free up resources. Swift handles the memory management of instances through automatic reference counting (ARC), as described in Automatic Reference Counting. Typically you don’t need to perform manual cleanup when your instances are deallocated. However, when you are working with your own resources, you might need to perform some additional cleanup yourself. For example, if you create a custom class to open a file and write some data to it, you might need to close the file before the class instance is deallocated.
当你不再需要一个实例的时候,swift会自动撤销它,以释放资源。swift是通过arc(自动引用计数)来管理实例的内存的。一般来说,当你的实例被撤销的时候,你不需要手动执行清理工作。但是,如果你要处理你自己的资源时,你或许需要自己做些额外的清理工作。比如,如果你创建了一个自定义的类来打开一个文件,并向这个文件写入了一些数据,那么你就需要在这个类实例被撤销前关闭文件。
Class definitions can have at most one deinitializer per class. The deinitializer does not take any parameters and is written without parentheses:
每个类的类定义最多只能有一个析构函数。析构函数没有参数,也没有括号:
deinit {
// 执行析构操作
}
Deinitializers are called automatically, just before instance deallocation takes place. You are not allowed to call a deinitializer yourself. Superclass deinitializers are inherited by their subclasses, and the superclass deinitializer is called automatically at the end of a subclass deinitializer implementation. Superclass deinitializers are always called, even if a subclass does not provide its own deinitializer.
析构函数在实例撤销之前自动调用。你不能自己调用析构函数。子类会继承父类的析构函数,而且父类的析构函数会在子类的析构函数的最后自动调用。即使子类没有提供析构函数,父类的析构函数也会被调用。
Because an instance is not deallocated until after its deinitializer is called, a deinitializer can access all properties of the instance it is called on and can modify its behavior based on those properties (such as looking up the name of a file that needs to be closed).
由于一个实例直到它的析构函数被调用了,它才会被销毁,因此,一个析构函数可以获取该实例的所有属性,并且可以修改它的行为(比如查询一个需要被关闭的文件的名字)
析构实战
Here’s an example of a deinitializer in action. This example defines two new types, Bank and Player, for a simple game. The Bank class manages a made-up currency, which can never have more than 10,000 coins in circulation. There can only ever be one Bank in the game:
举个例子。例子中定义了两个新的类型,Bank 和 Player。Bank类管理一个虚构的货币,价值不能超过10000coins。在例子中只能有一个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 keeps track of the current number of coins it holds with its coinsInBank property. It also offers two methods—distribute(coins:) and receive(coins:)—to handle the distribution and collection of coins.
Bank通过coinsInBank属性查询当前coins的数量。它提供了两个方法--distribute(coins:) 和 receive(coins:)—来处理coins 的分发(distribution)和回收(collection).
The distribute(coins:) method checks that there are enough coins in the bank before distributing them. If there are not enough coins, Bank returns a smaller number than the number that was requested (and returns zero if no coins are left in the bank).
distribute(coins:)方法检查在分发coins之前银行中是否有足够的coin。如果coins不够,bank就返回一个比要求的数字小的数字(如果银行中没有coins了就返回0)。
The receive(coins:) method simply adds the received number of coins back into the bank’s coin store.
receive(coins:)方法把收到的coins的数量加到银行保存的coin上去。
The Player class describes a player in the game. Each player has a certain number of coins stored in their purse at any time. This is represented by the player’s coinsInPurse property:
Player类定义了一个玩家。每个玩家在任何时候,钱包里都有一定数量的coins。这由玩家的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)
}
}
Each Player instance is initialized with a starting allowance of a specified number of coins from the bank during initialization, although a Player instance may receive fewer than that number if not enough coins are available.
每个Player实例初始化时都会得到一个初始的coins的数量值。
The Player class defines a win(coins:) method, which retrieves a certain number of coins from the bank and adds them to the player’s purse. The Player class also implements a deinitializer, which is called just before a Player instance is deallocated. Here, the deinitializer simply returns all of the player’s coins to the bank:
Player类定义了一个win(coins:)方法,此方法从bank接收一定数量的coins,并把它们加入玩家的钱包。Player类还实现了一个析构函数。此函数在Player实例被撤销前调用。在这个例子中,析构函数只是返回了该玩家在银行中的所有coins:
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"
A new Player instance is created, with a request for 100 coins if they are available. This Player instance is stored in an optional Player variable called playerOne. An optional variable is used here, because players can leave the game at any point. The optional lets you track whether there is currently a player in the game.
创建了一个Player实例,请求了100个coin如果有这么多的话。这个Player实例保存为一个可选的Player变量playerOne。之所以用可以变量,是因为players可以随时退出。可选类型可以让你检查当前是否有一个玩家(player).
Because playerOne is an optional, it is qualified with an exclamation mark (!) when its coinsInPurse property is accessed to print its default number of coins, and whenever its win(coins:) method is called:
由于playerOne 是可选的,因此当获取它的coinsInPurse属性来打印它的coins的默认值时,要加上感叹号(!),以及调用它的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"
Here, the player has won 2,000 coins. The player’s purse now contains 2,100 coins, and the bank has only 7,900 coins left.
这里,playerOne赢了2000coins。playerOne的钱包现在有2100个coins,银行现在还剩7900个coins。
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"
The player has now left the game. This is indicated by setting the optional playerOne variable to nil, meaning “no Player instance.” At the point that this happens, the playerOne variable’s reference to the Player instance is broken. No other properties or variables are still referring to the Player instance, and so it is deallocated in order to free up its memory. Just before this happens, its deinitializer is called automatically, and its coins are returned to the bank.
现在playerOne退出。这是因为把可选的playerOne变量设为nil。意味着“没有Player实例了”。这时候,playerOne变量指向Player实例的引用不存在了。现在没有其他的属性或变量继续指向那个Player实例,所以它就被销毁了,以释放它的内存。在这些操作之前,会调用析构函数,把它的coins返回给银行(bank).