Deinitializer вызывается непосредственно перед экземпляром класса освобождаться. Вы пишете деинициализаторы с deinit
ключевым словом, подобно тому, как инициализаторы пишутся с init
ключевым словом. Деинициализаторы доступны только для типов классов.
Как работает деинициализация
Swift автоматически освобождает ваши экземпляры, когда они больше не нужны, чтобы освободить ресурсы. Swift управляет памятью экземпляров с помощью автоматического подсчета ссылок ( ARC ). Обычно вам не нужно выполнять ручную очистку, когда ваши экземпляры освобождаются. Однако, когда вы работаете с собственными ресурсами, вам может потребоваться выполнить дополнительную очистку самостоятельно. Например, если вы создаете пользовательский класс, чтобы открыть файл и записать в него некоторые данные, вам может потребоваться закрыть файл до освобождения экземпляра класса.
Определения классов могут иметь не более одного деинициализатора на класс. Деинициализатор не принимает никаких параметров и записывается без скобок:
deinit {
// perform the deinitialization
}
Деинициализаторы вызываются автоматически, непосредственно перед освобождением экземпляра. Вы не можете вызывать деинициализатор самостоятельно. Деинициализаторы суперкласса наследуются их подклассами, и деинициализатор суперкласса вызывается автоматически в конце реализации деинициализатора подкласса. Деинициализаторы суперкласса всегда вызываются, даже если подкласс не предоставляет свой собственный деинициализатор.
Поскольку экземпляр не освобождается до тех пор, пока не будет вызван его деинициализатор, деинициализатор может получить доступ ко всем свойствам экземпляра, к которому он вызван, и может изменить свое поведение на основе этих свойств (например, поиск имени файла, который необходимо закрыть). ).
Деинициализаторы в действии
Вот пример деинициализатора в действии. Этот пример определяет два новых типа 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
экземпляр освобождаться. Здесь деинициализатор просто возвращает все монеты игрока в банк:
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
экземпляр хранится в необязательной Player
переменной с именем playerOne
. Здесь используется необязательная переменная, потому что игроки могут покинуть игру в любой момент. Опционально позволяет отслеживать, есть ли в данный момент игрок в игре.
Поскольку playerOne
это необязательно, он квалифицируется восклицательным знаком ( !
), когда к его coinsInPurse
свойству обращаются, чтобы напечатать количество монет по умолчанию и всякий раз, когда 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"
Здесь игрок выиграл 2000 монет. Теперь кошелек игрока содержит 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
экземпляр, поэтому он освобождается для освобождения памяти. Непосредственно перед тем, как это произойдет, его деинициализатор вызывается автоматически, а его монеты возвращаются в банк.
0 комментариев