🔥 Deinitializer 사용 예제

652자
8분

Swift에서는 클래스의 인스턴스가 메모리에서 해제되기 직전에 deinitializer라는 특별한 메서드를 호출할 수 있습니다. Deinitializer는 인스턴스가 더 이상 필요하지 않을 때 수행해야 할 정리 작업을 처리하는 데 사용됩니다. 지금부터 간단한 게임을 예로 들어 deinitializer가 실제로 어떻게 동작하는지 살펴보겠습니다.

Bank 클래스

먼저, Bank라는 클래스를 정의해 볼까요? 이 클래스는 가상의 화폐를 관리하는 역할을 합니다. 게임 내에서는 최대 10,000개의 코인만 유통될 수 있고, 단 하나의 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
    }
}
swift

BankcoinsInBank 속성을 통해 현재 보유하고 있는 코인의 개수를 추적합니다. 그리고 distribute(coins:)receive(coins:) 두 개의 메서드를 제공하여 코인의 분배와 수집을 처리합니다.

distribute(coins:) 메서드는 요청받은 코인의 개수가 은행에 충분히 있는지 확인한 후에 분배합니다. 만약 충분한 코인이 없다면, Bank는 요청받은 개수보다 적은 수의 코인을 반환하고 (은행에 남아있는 코인이 없다면 0을 반환), 실제로 제공된 코인의 개수를 나타내는 정수 값을 반환합니다.

receive(coins:) 메서드는 단순히 받은 코인의 개수를 은행의 코인 저장소에 다시 추가합니다.

Player 클래스

이제 Player 클래스를 정의해 보겠습니다. 이 클래스는 게임에서 플레이어를 나타내죠. 각 플레이어는 항상 일정 개수의 코인을 지갑에 보관하고 있습니다. 이는 플레이어의 coinsInPurse 속성으로 표현됩니다.

class Player {
    var coinsInPurse: Int
 
    // 초기화 시 은행에서 지정된 개수의 코인을 받음
    init(coins: Int) {
        coinsInPurse = Bank.distribute(coins: coins)
    }
 
    // 게임에서 이겨 코인을 획득하는 메서드
    func win(coins: Int) {
        coinsInPurse += Bank.distribute(coins: coins)
    }
 
    // 플레이어 인스턴스가 메모리에서 해제되기 직전에 호출되는 deinitializer
    deinit {
        Bank.receive(coins: coinsInPurse)
    }
}
swift

Player 인스턴스는 초기화 과정에서 은행으로부터 지정된 개수의 코인을 시작 자금으로 받습니다. 다만, 은행에 충분한 코인이 없다면 요청한 개수보다 적은 코인을 받을 수 있습니다.

Player 클래스는 win(coins:) 메서드를 정의하여, 게임에서 이겨 은행으로부터 일정 개수의 코인을 가져와 플레이어의 지갑에 추가합니다. 또한, Player 클래스는 deinitializer를 구현하고 있는데, 이는 Player 인스턴스가 할당 해제되기 직전에 호출됩니다. 여기서 deinitializer는 단순히 플레이어의 모든 코인을 은행에 반환하는 역할을 합니다.

게임 시작

이제 게임을 시작해 볼까요? 먼저 Player 인스턴스를 생성하고, 사용 가능한 코인이 있다면 100개의 코인을 요청합니다. 이 Player 인스턴스는 playerOne이라는 옵셔널 Player 변수에 저장됩니다. 여기서 옵셔널 변수를 사용한 이유는 플레이어가 언제든 게임을 떠날 수 있기 때문입니다. 옵셔널을 사용하면 현재 게임에 플레이어가 있는지 추적할 수 있습니다.

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

playerOne은 옵셔널이므로, coinsInPurse 속성에 접근하여 기본 코인 개수를 출력할 때와 win(coins:) 메서드를 호출할 때마다 느낌표(!)로 옵셔널을 강제 언래핑합니다.

게임 진행

playerOne!.win(coins: 2_000)
print("PlayerOne won 2000 coins & now has \(playerOne!.coinsInPurse) coins")
// "PlayerOne won 2000 coins & now has 2100 coins" 출력
print("The bank now only has \(Bank.coinsInBank) coins left")
// "The bank now only has 7900 coins left" 출력
swift

위 코드에서 플레이어는 2,000개의 코인을 획득했습니다. 이제 플레이어의 지갑에는 2,100개의 코인이 들어있고, 은행에는 7,900개의 코인만 남아있네요.

게임 종료

playerOne = nil
print("PlayerOne has left the game")
// "PlayerOne has left the game" 출력
print("The bank now has \(Bank.coinsInBank) coins")
// "The bank now has 10000 coins" 출력
swift

이제 플레이어가 게임을 떠났습니다. 이는 옵셔널 playerOne 변수를 nil로 설정하여 나타냅니다. nil은 "Player 인스턴스가 없음"을 의미하죠. 이 시점에서 playerOne 변수의 Player 인스턴스에 대한 참조가 끊어집니다. 다른 속성이나 변수가 더 이상 Player 인스턴스를 참조하지 않으므로, 메모리를 해제하기 위해 할당 해제됩니다. 할당 해제되기 직전에 deinitializer가 자동으로 호출되어 플레이어의 코인을 은행에 반환합니다.

이렇게 간단한 게임을 통해 deinitializer가 어떻게 동작하는지 살펴보았습니다. Deinitializer는 클래스 인스턴스가 메모리에서 해제되기 직전에 호출되어 정리 작업을 수행하는 유용한 도구입니다.

게임 예제에서는 Player 인스턴스가 게임을 떠날 때 자동으로 deinitializer를 호출하여 플레이어의 코인을 은행에 반환했습니다. 이처럼 deinitializer를 적절히 활용하면 메모리 관리와 리소스 정리를 보다 효과적으로 수행할 수 있습니다.