En este Tutorial Swift aprenderemos sobre la herencia de inicializadores. En Swift y a diferencia de Objective-C, las subclases no heredan automáticamente los inicializadores de sus clases padre. El enfoque de Swift es evitar la situación donde un inicializador bien básico es heredado por una subclase más especializada para luego ser usado en la creación de una instancia de la subclase, instancia que puede no haberse inicializado completamente o no de la manera correcta.

Sobreescritura de inicializadores

Cuando definimos el inicializador de una subclase y este coincide con un inicializador designado de la clase padre, nos encontramos sobreescribiendo este inicializador designado. Por lo tanto tenemos que escribir la palabra clave override antes de la definición del inicializador.

Por el contrario cuando estamos declarando un inicializador en nuestra subclase y este coincide con el inicializador de conveniencia de la clase padre, pues ese inicializador de la clase padre jamás podrá ser llamado directamente por la subclase, por lo que técnicamente hablando no estaríamos sobreescribiendo el inicializador de conveniencia de la clase padre.

Como es habitual vamos a un ejemplo para entender de mejor manera lo antes comentado. En este ejemplo definimos la clase base Vehicle. Esta clase declara una propiedad almacenada llamada numberOfWheels, con un valor por defecto de 0. Esta propiedad es usada por otra computada de nombre description para crear un String con las características del vehículo:

Esta clase establece un valor por defecto a su única propiedad almacenada y no provee de ningún inicializador. Como resultado de esto, automáticamente recibe un inicializador por defecto, inicializador que cuando está disponible siempre es de tipo designado y puede ser usado para crear una instancia de Vehicle con un numberOfWheels de 0:

Proseguimos por crear otra clase, una subclase de Vehicle llamada Bicycle:

La subclase Bicycle declara un inicializador designado, init(). Este inicializador designado coincide con su homólogo de la clase padre Vehicle, por esto en el caso de Bicycle el inicializador está marcado con el modificado override.

El inicializador designado de Bicycle comienza por la llamada super.init(), es decir inicia por delegar hacia su clase padre. Esto nos asegura que la propiedad heredada numberOfWheels sea inicializada por Vehicle antes de que Bicycle tenga la oportunidad de modificarla. En caso de que se pregunten que sucedería si intentemos hacer uso de numberOfWheels antes de la ejecución del inicializador designado de la clase padre, pues el compilador nos arroja el siguiente mensaje de error:

Use of ‘self’ in property access ‘numberOfWheels’ before super.init initializes self

Luego de esta primera instrucción de la línea 5 el valor de la propiedad (en este punto cero) es reemplazado por el valor 2. Así que cuando creamos una instancia de Bicycle y llamamos a la propiedad heredada description podemos ver a que valor ha sido actualizado el número de ruedas:

…la salida en pantalla sería:

Herencia automática de inicializadores

Como hemos mencionado arriba, las subclases no heredan los inicializadores por defecto. No obstante, los inicializadores de las clases padres son automáticamente heredados bajo ciertas condiciones. En la practica, esto significa que en muchos escenarios comunes no necesitamos sobreescribir los inicializadores, podremos heredar los inicializadores de las clases padres, siempre que sea seguro hacerlo.

Asumiendo que establezcamos valores por defecto por cada nueva propiedad que añadimos a una subclase, las siguientes dos reglas se aplican:

  • Regla 1: Si la subclase no define ningún inicializador designado, este automáticamente hereda todos los inicializadores designados de su clase padre.
  • Regla 2: Si la subclase provee una implementación de todos los inicializadores designados de su clase padre – ya sea heredándolas por la regla 1 o declarando una implementación personalizada como parte de su definición – entonces automáticamente hereda todos los inicializadores de conveniencia de su clase padre.

Estas reglas se aplican incluso si la subclase añade inicializadores de conveniencia.

Con este artículo, por ahora, creo haber cubierto todo lo referente a los inicializadores en el lenguaje Swift, en caso de que no hayan consultados las anteriores entregas, aquí tienen las referencias:

Otra fuente de necesaria consulta y de donde se ha nutrido este artículo es la documentación oficial de Apple, el apartado referente a los inicializadores en Swift (Ingles).

Para más información y ejemplos podemos dirigirnos a la documentación oficial de Swift (Ingles) en el sitio de desarrolladores de Apple.

Espero que todo cuanto se ha dicho aquí, de una forma u otra le haya servido de aprendizaje, de referencia, que haya valido su preciado tiempo.

Este artículo, al igual que el resto, será revisado con cierta frecuencia en pos de mantener un contenido de calidad y actualizado.

Cualquier sugerencia, ya sea errores a corregir, información o ejemplos a añadir será, más que bienvenida, necesaria!