Observers en Swift: willSet y didSet

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

Resumen

Domina cómo reaccionar a cambios en tus propiedades en Swift con property observers. Verás cuándo usar willSet y didSet, cómo se diferencian de una stored property y por qué recuerdan a las computed properties. Un ejemplo práctico con un podómetro ilustra el flujo completo, y un reto final consolida el aprendizaje.

¿Qué son los property observers y cuándo usarlos?

Los property observers se añaden a una propiedad para ejecutar lógica antes y después de cambiar su valor. Son ideales cuando necesitas validar rangos, lanzar notificaciones o imprimir mensajes al modificar datos. Ejemplo clásico: una propiedad de vida en un videojuego que no debe bajar de cero para evitar game over.

En propiedades de una estructura o una clase, puedes definir dos observadores: willSet (futuro) y didSet (pasado). Permiten “escuchar” cambios sin convertir la propiedad en una computed property.

¿Cómo se diferencian willSet y didSet?

  • willSet: se ejecuta justo antes de cambiar el valor. Recibe el nuevo valor, que puedes nombrar, por ejemplo, como newTotalSteps.
  • didSet: se ejecuta justo después del cambio. Expone el valor anterior mediante oldValue.

En síntesis: antes de asignar, willSet; después de asignar, didSet.

¿Cómo se relacionan con computed properties?

Comparten la idea de “reaccionar” al acceso o cambio, pero aquí la propiedad es almacenada (stored property). Es decir, guardas el valor y, además, observas sus cambios con willSet/didSet.

¿Cómo implementar un StepCounter con observers en Swift?

Un podómetro necesita contar pasos y avisar de incrementos. Con una clase StepCounter y una stored property totalSteps, willSet imprime el nuevo total y didSet calcula el incremento usando oldValue.

class StepCounter { var totalSteps: Int = 0 { willSet(newTotalSteps) { print("El número de pasos va a subir hasta \(newTotalSteps)") } didSet { if totalSteps > oldValue { print("El número de pasos ha incrementado en \(totalSteps - oldValue)") } } } } let stepCounter = StepCounter() stepCounter.totalSteps = 200 // mensajes: "va a subir hasta 200"; "ha incrementado en 200". stepCounter.totalSteps = 520 // mensajes: "va a subir hasta 520"; "diferencia 320". stepCounter.totalSteps += 1234 // total 1754; incremento de 1234.

Claves del ejemplo:

  • Propiedad almacenada: totalSteps inicia en 0.
  • willSet: anuncia el nuevo valor antes de asignarlo.
  • didSet: usa oldValue para calcular el incremento.
  • Mensajes claros: motivan al usuario e informan del progreso.

¿Qué práctica refuerza el control de rangos con observers?

Pon en práctica el patrón de validación con un atributo de vida del jugador. Objetivo: mantenerla dentro de 0 a 100 y comunicar estados críticos.

Sugerencias para el reto:

  • Crea una clase con una propiedad vida inicial. Controla cambios con willSet o didSet.
  • Límite superior: si supera 100, corrige el valor para que no pase de 100.
  • Límite inferior: si baja de 0, muestra un mensaje de game over.
  • Piensa en qué punto validar: antes con willSet o después con didSet, según tu flujo.

Habilidades que entrenas:

  • Modelado de estado con propiedades y clases.
  • Validación de rangos y corrección de valores.
  • Uso de observers: willSet, didSet, oldValue.
  • Salida informativa con print y lógica condicional.

¿Te animas a extenderlo con contadores de eventos o notificaciones? Comparte tu implementación y dudas en comentarios.