새로 배운 점
- 슈퍼 클래스의 소멸자는 슈퍼클래스의 서브클래스에 의해 상속되고, 슈퍼클래스의 소멸자는 자동으로 서브클래스의 소멸자의 끝에 호출됩니다.
Deinitialization
Deinitialization는 클래스 인스턴스가 해제될 때 즉시 호출됩니다.
Deinitialization는 deinit 키워드를 사용하여 작성할 수 있으며,
init 키워드를 사용하여 이니셜라이저를 작성하는 방법과 유사합니다.
Deinitialization는 오직 class 타입에서만 사용할 수 있습니다.
How Deinitialization Works
Swift는 인스턴스가 더이상 필요 없을 때 자동으로 인스턴스를 할당 해제하여 리소스를 해제합니다.
Swift는 인스턴스의 메모리 관리를 Automatic Reference Counting(ARC)을 통해 관리합니다.
일반적으로 수작업으로 해제할 필요가 없습니다.
그러나 인스턴스 자체 리소스를 가지고 작업할 때, 몇 가지 해제 작업이 수행할 필요가 있을 때도 있습니다.
예를 들어, 만약 파일을 열고 data를 파일에 작성하는 클래스를 생성한다면,
인스턴스가 해제되기 전에 파일을 닫는 것이 필요합니다.
클래스 정의에서 최대 하나의 소멸자(deinitializer)를 가질 수 있습니다.
소멸자는 어떠한 파라미터도 전달 받지 않으며, 괄호 없이 작성됩니다.
deinit {
// perform the deinitialization
}
소멸자는 자동으로 호출되며, 인스턴스 할당 해제가 발생하기 전에 호출됩니다.
직접 소멸자를 호출할 수 없습니다.
슈퍼 클래스의 소멸자는 슈퍼클래스의 서브클래스에 의해 상속되고,
슈퍼클래스의 소멸자는 자동으로 서브클래스의 소멸자의 끝에 호출됩니다.
서브클래스가 자신만의 소멸자를 가지고 있지 않더라도 슈퍼클래스의 소멸자는 항상 호출됩니다.
인스턴스는 소멸자가 호출될 때까지 해제되지 않으므로,
소멸자는 호출된 인스턴스의 모든 프로퍼티에 접근할 수 있으며
이러한 프로퍼티들을 기반으로 동작을 수정할 수 있습니다.
Deinitializers in Action
아래의 코드는 소멸자 예제입니다.
이 코드에서는 간단한 게임을 위해 Back와 Player 두 개의 클래스를 정의합니다.
Back 클래스는 현재 코인의 개수를 추적하고 이를 coinsInBack 프로퍼티에 저장합니다.
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
}
}
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 클래스는 인스턴스가 해제되기 전에 호출되는 소멸자도 구현합니다.
이는 플레이어의 모든 코인을 은행에 반납하도록 구현되어 있습니다.
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 메서드를 호출할 때마다 느낌표를 붙여줘야 합니다.
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"
플레이어가 게임을 떠나면 nil로 설정되면서 인스턴스의 참조가 깨집니다.
Player 인스턴스를 참조하는 다른 프로퍼티나 변수가 없으므로 메모리를 확보하기 위해서 인스턴스의 할당이 해제됩니다.
해제 되기 직전에 소멸자가 자동 호출되고 인스턴스의 코인은 다시 은행으로 반환됩니다.
참고
https://docs.swift.org/swift-book/LanguageGuide/Deinitialization.html