Destructores en Programación: Liberación de Recursos Automática

Clase 22 de 27Curso de Programación Orientada a Objetos en Swift

Resumen

Controla la memoria y los recursos en Swift con seguridad: el desinicializador permite limpiar automáticamente objetos asociados cuando un objeto principal se destruye. Con un ejemplo práctico de un banco y un jugador, verás cómo retornar monedas al sistema al finalizar su ciclo de vida evita residuos en memoria y estados incoherentes.

¿Qué es y cuándo usar el desinicializador en Swift?

El desinicializador se ejecuta cuando un objeto se destruye: su objetivo es limpiar y notificar a otras partes del sistema. Swift trae uno por defecto, pero conviene sobreescribirlo cuando debes devolver recursos compartidos o desregistrar dependencias. Imagina un jugador que muere mientras su inventario sigue vivo: ese inventario ocupa memoria sin valor. Al implementar deinit, el Player puede devolver al Bank todas las monedas que llevaba encima, manteniendo el estado consistente.

  • Evita objetos “pululando” sin uso en memoria.
  • Devuelve recursos compartidos al sistema de origen.
  • Reduce errores por estados desbalanceados.

¿Cómo construir Bank y Player para devolver monedas al destruirse?

La idea es simple: Bank guarda un saldo global con una variable static y expone dos métodos static: uno para distribuir monedas y otro para recibirlas. Player pide monedas al crearse con init y al ganar, siempre desde Bank. En deinit, devuelve lo que tenga en su monedero.

¿Cómo se distribuyen e ingresan monedas en Bank?

final class Bank {
    static var coinsInBank = 2000

    static func distribute(coinsRequested: Int) -> Int {
        let coinsToVend = min(coinsRequested, coinsInBank)
        coinsInBank -= coinsToVend
        return coinsToVend
    }

    static func receive(coins: Int) {
        coinsInBank += coins
    }
}
  • Saldo compartido con variable estática.
  • Distribución limitada al mínimo entre lo solicitado y lo disponible.
  • Recepción directa: siempre se puede ingresar.

¿Cómo el Player gana y devuelve monedas?

final class Player {
    var coinsInPurse: Int

    init(coins: Int) {
        self.coinsInPurse = Bank.distribute(coinsRequested: coins)
    }

    func win(coins: Int) {
        coinsInPurse += Bank.distribute(coinsRequested: coins)
    }

    deinit {
        Bank.receive(coins: coinsInPurse)
    }
}
  • Toma inicial de monedas en el init desde Bank.
  • Ganancias siempre mediadas por Bank.
  • Limpieza automática en deinit: se devuelven todas las monedas.

¿Cómo se usa con un optional para poder destruir al jugador?

var playerOne: Player? = Player(coins: 100)   // Bank pasa de 2000 a 1900.
playerOne!.win(coins: 2000)                   // Bank reparte lo que quede; puede llegar a 0.
playerOne = nil                               // deinit: Bank recupera todas las monedas del player.
// Bank vuelve a 2000 tras la destrucción del jugador.
  • Se usa optional para poder asignar nil y disparar el deinit.
  • Si fuera let o no optional, no podrías destruirlo manualmente.
  • Al morir o “irse a dormir” el jugador, el banco recupera automáticamente las monedas.

¿Qué habilidades y palabras clave refuerzas?

  • Desinicializador (deinit): se ejecuta al destruir un objeto y limpia recursos compartidos.
  • Inicializador (init): configura el estado pidiendo monedas al banco.
  • Variable y métodos estáticos (static): estado global del banco y operaciones centralizadas.
  • Transferencia de recursos: siempre que el jugador toma o gana, lo hace vía Bank.
  • Optional y nil: permiten destruir el objeto para activar deinit cuando convenga.
  • Control de disponibilidad: retirada limitada al mínimo entre pedido y saldo.
  • Consistencia del sistema: al destruir el jugador, el banco vuelve a su saldo inicial.

¿Te gustaría comentar otros escenarios donde deinit te ha ayudado a mantener el estado limpio en tus modelos de juego o apps?