Deinitializer는 클래스 인스턴스가 deallocate될 때 즉시 실행된다.
deinit
키워드를 붙여서 쓰고, 클래스에서만 쓸 수 있음!!
Swift는 인스턴스가 더 이상 사용되지 않는다고 판단되면 리소스를 반환해주기 위해 인스턴스를 deallocate한다.
보통은 직접 cleanup을 하지 않아도 되지만, 내 리소스를 사용할 때는 cleanup을 해줘야 할 때도 있음.
예를 들어 커스텀 클래스를 만들어서 파일을 열고 데이터를 집어넣는 데 쓴다면, 클래스 인스턴스가 deallocate되기 전에 파일을 닫아야 한다.
deinit은 매개변수를 가지지 않고, 클래스마다 최대 한 개만 가질 수 있음.
deinit {
// perform the deinitialization
}
얘네는 instance deallocation이 되기 직전에 자동으로 호출되고, 내가 직접 호출하는 건 불가능함.
슈퍼클래스의 디이셜라이저는 서브클래스에 상속되고, 서브클래스 디이니셜라이저가 끝난 후 실행된다. 서브클래스 디이니셜라이저가 없더라도 슈퍼클래스의 디이니셜라이저는 항상 실행됨.
당연히 디이니셜라이저가 끝난 후 인스턴스가 deallocate되기 때문에, 디이니셜라이저는 인스턴스의 모든 프로퍼티에 접근 가능함! 닫을 파일의 이름을 알아본다던가..
예제를 통해 아라보자.
간단한 게임임!
10,000코인 이상 가질 수 없는 Bank
클래스와 Player
클래스가 있음.
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:)
메소드는 요청된 코인의 갯수와 잔액을 비교해서 요청된 게 잔액보다 많다면 잔액을 반환하고, 적다면 요청된 만큼을 반환하고, 아예 없다면 0을 반환한다. 반환값(출금액)은 numberOfCoinsToVend
에 저장돼서 반환됨!
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)
}
}
플레이어마다 초기화 때 은행에서 코인을 지급받는데(distribute), 코인이 부족하면 초기화 때 써넣은 갯수보다 적게 받을수도 있음.
win(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"
새로운 플레이어가 생성되고, 100코인을 받는다. 옵셔널로 지정한 이유는 플레이어가 언제든 게임을 떠날 수 있기 때문! 요걸로 플레이어가 게임을 플레이하고 있는지 아닌지를 판단할 수 있다.
playerOne
이 옵셔널이기 때문에 사용할 때도 언래핑을 위해서 !
를 붙여줘야 함!
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코인을 땄을 때 플레이어의 잔액과 은행의 잔액을 위와 같이 확인할 수 있음.
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로 만들어지는데, playerOne
의 Player
클래스 인스턴스의 참조가 사라지는 거!
다른 프로퍼티나 변수가 Player
를 참조하고 있지 않으므로, 인스턴스가 deallocate 됨.
그래서 디이니셜라이저가 실행되고 은행으로 코인이 모두 돌아가는 것!