Comprender los inicializadores en Swift te permite crear jerarquías de clases robustas y predecibles. Aquí verás cómo funcionan los inicializadores designados y los inicializadores por conveniencia, cómo interactúan con la herencia, y por qué llamadas como super.init y override son claves para mantener un flujo de construcción correcto.
¿Qué son los inicializadores designados y de conveniencia en Swift?
Los inicializadores organizan el flujo de creación de objetos en clases y subclases. En herencia, ese flujo debe ser claro y seguro para que cada clase configure sus propias variables y las herede correctamente.
¿Qué reglas rigen el llamado de init en herencia?
Un inicializador designado solo puede llamar a un designado de la superclase.
Un inicializador de conveniencia solo puede llamar a otro init de la misma clase (de conveniencia o designado).
El último init llamado siempre debe ser designado. Si no, la inicialización fallará.
¿Cómo aplicarlas en clases y subclases con Vehicle y Bicycle?
Partimos de una clase base con un valor por defecto y una propiedad computada. Así, no es obligatorio escribir un init explícito para la clase padre.
¿Cómo se inicializa Vehicle y qué imprime description?
description devuelve un texto basado en el número de ruedas.
¿Por qué override init debe llamar a super.init en Bicycle?
Al sobreescribir con override, el init del hijo sustituye al del padre. Para mantener el orden correcto, el designado del hijo debe delegar en el designado del padre con super.init.
override init indica que el hijo redefine el proceso.
super.init() asegura que el padre prepare su parte antes de ajustar las del hijo.
¿Cómo fluye un inicializador de conveniencia con HoverBoard y color?
Cuando el hijo introduce propiedades propias, como un color, se puede usar un flujo de conveniencia: primero se configuran las variables del hijo y, de forma implícita, se llama al init del padre para completar la estructura base. Luego se puede personalizar la salida combinando la descripción del padre con los datos del hijo.
¿Cómo combina HoverBoard sus propiedades con la descripción del padre?
classHoverBoard:Vehicle{var color:Stringinit(color:String){self.color = color
// Flujo descrito: se inicializa la superclase.super.init()}overridevar description:String{return"\(super.description) en color \(self.color)"}}let hoverboard =HoverBoard(color:"silver")print(hoverboard.description)// "0 ruedas en color silver"
color es propio de HoverBoard y se configura con self.color = color.
super.description reutiliza la descripción del padre y la enriquece con el color.
El resultado muestra cómo el init del padre fija las ruedas en 0 y el hijo añade su detalle.
¿Tienes ejemplos propios con subclases y override que quieras validar? Cuéntalos y probamos juntos el flujo de inicialización con super.init y descripciones personalizadas.
Algo que falto mencionar es que cuando se hereda de una clase padre, y se intenta modificar el valor de una propiedad en la clase hijo por medio de una inicializador por conveniencia primer se tiene que llenar las propiedades pasadas a dicho inicializador, despues llamar al super.init() y despues modificar el valor en cuestion.
lo mismo aplica si no es un inicializador por conveniencia
Tienes toda la razón Alfredo, gracias por la aclaración. Siento que el ejemplo del profesor se queda corto para mostrar como funcionan los inicializadores de conveniencia de una forma estándar.
Para los inicializadores con herencia, se deben cumplir las siguientes condiciones de manera obligatoria:
Un inicializador designado llama a un designado de la super clase (implícita o explícitamente)
Un inicializador por conveniencia solo puede llamar a otro de la misma clase
El último init que se llame siempre debe ser designado
y que pasa si declaro un inicializador por conveniencia en la clase padre?
Buen punto
Tomando en cuenta lo que menciona @Alfredo Gonzales:
Si quieres tomar la propiedad de numberOfWheels para la clase hija (Hoverboard) deberás llamar explicitamente al super.init() de la clase padre y así hacerla propia para esta subclase (no la sobreescribes)
// Designated inits and for convenienceclassVehicle{var numberOfWheels =0vardescription:String{return"\(numberOfWheels) wheels"}}let vehicle =Vehicle()vehicle.descriptionclassBicycle:Vehicle{ override init(){super.init() numberOfWheels =2}}let bicycle =Bicycle()bicycle.descriptionclassHoverboard:Vehicle{varcolor:String// Convenienceinit(color:String){ self.color= color
super.init() numberOfWheels =5// Implicit call to super.init} override vardescription:String{return"\(super.description) in the color \(self.color)"}}let hoverboard =Hoverboard(color:"Silver")hoverboard.description
les comparto mi código jugando un poco con los inicializadores
classVehicle{var numberOfWeels =0vardescription:String{return"numero de ruedas: \(numberOfWeels)"}}classBicycle:Vehicle{varcolor:Stringvartipo:Stringinit(color:String,tipo:String){ self.color= color
self.tipo= tipo
//se llama por defecto super.init()} override vardescription:String{return"Bicycleta color: \(self.color) de tipo: \(self.tipo) numero de ruedas: \(super.numberOfWeels)"}}let bicycle =Bicycle(color:"morado",tipo:"normal")bicycle.numberOfWeelsbicycle.colorprint(bicycle.description)