El tema de hoy son los inicializadores o constructores, como también se les conoce en otro lenguajes de programación. En este Tutorial Swift aprenderemos específicamente sobre los inicializadores más básicos, tanto en las clases como en las estructuras, veremos sus características, su forma de uso y como pueden trabajar en conjunto.

Inicializadores por Defecto

Swift proporciona un inicializador por defecto para cualquier estructura o clase, el cual proporciona valores por defecto para todas las propiedades. Este inicializador simplemente crea una nueva instancia y establece todas las propiedades a sus valores predeterminados.

En el siguiente ejemplo definimos una clase llamada ShoppingListItem, que encapsula el nombre, cantidad y estado de compra de un artículo en una lista de la compra:

Debido a que todas las propiedades de la clase ShoppingListItem tienen valores por defecto, y porque es una clase base y por ende sin superclase, ShoppingListItem obtiene automáticamente del compilador un inicializador por defecto el cual crea una nueva instancia con todas sus propiedades establecidas con los valores predeterminados. Si se han percatado a la propiedad name no le hemos especificado un valor por defecto, pues resulta que como esta es opcional recibe automáticamente del compilador el valor predeterminado nil.

Inicializadores de Miembro por Miembro

Las estructura reciben automáticamente un inicializador de miembro por miembro si estas no definen un inicializador. A diferencia de un inicializador por defecto, el compilador otorga a la estructura un inicializador de miembro por miembro, incluso si a las propiedades no se les ha establecido valores por defecto.

El inicializador de miembro por miembro es una manera abreviada de inicializar las propiedades miembros de las nuevas instancias de la estructura. Es decir que los valores iniciales de las propiedades de la nueva instancia se pueden pasar al inicializador de miembro por miembro haciendo uso del nombre de cada propiedad.

Veamos un ejemplo donde esto quede más claro:

…en el ejemplo se define una estructura llamada Size con dos propiedades denominadas width y height. Ambas propiedades se infieren a ser de tipo doble mediante la asignación de un valor predeterminado de 0,0. Dada esta declaración la estructura recibe automáticamente un inicializador init (widthheight: ) que podemos utilizar para inicializar una nueva instancia, tal y como hacemos en la última línea.

Delegación de Inicializadores para Tipos por Valor

Los inicializadores pueden hacer llamadas a otros en pos de que este último complemente la inicialización de una instancia. Este proceso se conoce como delegación de inicializadores y evita la duplicidad de código a través de múltiples inicializadores.

Las reglas de como esta delegación funciona difieren entre los tipos por valor y las clases. Los tipos por valor (Estructuras, Enumeraciones,…) no soportan herencia por lo que la delegación de inicializadores en estos tipos funciona de manera muy simple ya que solamente pueden delegar hacia otro inicializador que ellos mismos provean. Las clases sin embargo pueden heredar de otras clases y esto trae consigo la responsabilidad de cerciorarse de que a todas las propiedades miembros que estas heredan les sea asignado un valor durante este proceso.

Hay que hacer notar que cuando definimos un inicializador personalizado automáticamente este toma el lugar del inicializador por defecto (o el inicializador de miembro por miembro en el caso de las estructuras) para ese tipo.

En el siguiente ejemplo creamos una estructura llamada Size la cual representa un tamaño con valores de ancho y altura, luego creamos otra llamada Point y que como deben haber inferido viene a representar un punto con sus respectivos valores de coordenadas cartesianas:

Continuamos con la estructura Rect que representa un rectángulo y que puede ser inicializada de tres formas, usando su inicializador por defecto, inicializando las propiedades origin y size o especificando un punto central y un tamaño. Estas opciones de inicialización están representadas por tres inicializadores personalizados que forman parte de la definición de la estructura:

El primer inicializador init(), el de la línea 6, se encarga del caso en que no pasemos valores:

El segundo, init(origin:size:) es funcionalmente  similar al inicializador de miembro por miembro que la estructura hubiera recibido si esta no tuviera su propio inicializador personalizado:

El tercer inicializador init(center:size:) es un poco más complejo. Este comienza por calcular el punto de origen basado en el un punto central y un valor de tamaño, para luego llamar o delegar hacia el inicializador init(origin:size:) el cual almacenará los nuevos valores de origen y tamaño.

Evidentemente el inicializador init(center:size:) pudo haber almacenado los valores de origen y tamaño directamente en las propiedades respectivas, pero habiendo un inicializador que ya provee de esta función es más conveniente (y claro en la intención) delegar esta tarea al mismo tiempo que nos evitamos dos líneas de código extra y para colmo repetidas.

En próximos artículos veremos otros tipos de inicializadores, como los falibles, quizás más avanzados y que por su importancia he preferido dedicarles un artículo completo.

Para más información y ejemplos podemos dirigirnos a la documentación oficial de Swift (Inglés) 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!