Home » Cursos » Swift 2 Lección 7, Structs o estructuras
Curso Swift Lección 7

Swift 2 Lección 7, Structs o estructuras

Compra "Aprendiendo Swift 3"

La presente lección está probada y certificada en su funcionamiento con la versión 7 o superior de Xcode y corresponde a la especificación 2 y 2.1 del lenguaje Swift.
En la lección 3 hablamos sobre los structs como una parte de las posibles estructuras del lenguaje Swift, pero los protagonistas eran las clases y estos casi no tuvieron protagonismo. Ahora creo que debemos darle una lección completa a este nuevo tipo de estructura de programación, también porque es un pilar básico de Swift 2.0 y su programación orientada a protocolos. Si usamos este paradigma, los structs pueden representar un sustituto natural de las clases y presentar todo un nuevo mecanismo de abstracción a la hora de desarrollar.

Datos por valor o por referencia

Un struct es básicamente, una estructura de datos o al menos ese es su objetivo o representación. Pero vista desde un punto de vista más amplio a nivel de Swift podemos pensar que un struct es un realidad una clase sin herencia y cuyo principal objetivo es crear una estructura de código que pueda ser representada a partir de un tipo de dato por valor y no por referencia.

Mientras los tipos de dato por referencia suponen la base de la orientación a objetos, donde una variable o constante no contiene el dato en sí, si no la dirección de memoria (o referencia) donde esté el objeto almacenado, un struct es un dato por valor donde el dato en sí está almacenado en la variable o constante directamente. Es básicamente la diferencia entre apuntar el cajón donde guardamos las cosas en una lista donde en cada línea enumeramos todos los cajones de un inventario y lo que contienen (por referencia) o a ponerle una etiqueta directamente al cajón para saber qué hay dentro (por valor).

A efectos de programación, asignar una variable con un dato por referencia a otra (un objeto creado a partir de una clase), hace que ambas variables apunten y hablen del mismo objeto. Pero en un struct esto no es así: al igual que un array o cualquier tipo de colección de Swift, dato numérico o cadena, cuando se asigna una variable con un struct a otra, en realidad estamos haciendo una copia idéntica que, a partir del momento de la copia, se convierten en dos estructuras de datos completamente independientes y sin relación alguna, salvo en su definición base.

Struct, inicializadores por defecto

Cuando creamos un struct no necesitamos crear un inicializador si no simplemente decir qué datos queremos almacenar en el mismo como propiedades o qué métodos queremos que le acompañen. Nada más. Imaginemos una estructura para una entrada básica en una agenda de contactos.

Simplemente hemos dicho qué propiedades queremos, el tipo de las mismas y nada más. Ahora ya podemos crear estructuras de este tipo y no necesitamos inicializador alguno, ni asignar valor a las propiedades como en una clase. Con esta simple estructura tenemos un tipo de dato por variable, complejo, que podemos utilizar a través de un inicializador por defecto (o sintetizado) creado por ella misma y que nos permite empezar a trabajar.

Structs 01

Cuando creamos una nueva variable y decimos que sea un tipo struct Agenda, al escribir el primer paréntesis el sistema ya nos permite elegir en su ayuda en línea la creación del constructor por defecto donde vamos a darle valor a todas y cada una de las propiedades no opcionales del mismo.

Este inicializador por defecto utiliza en todos sus parámetros nombres externos, para que sepamos bien a qué propiedades vamos a dar valor. En este caso, hemos de tener muy presente (en contra de lo que pasaría con un objeto creado a partir de una clase) que si definimos el struct como constante (let), estamos haciendo el dato inmutable y por lo tanto no podremos modificar ningún valor de sus propiedades una vez inicializado. El motivo es claro: lo que hay en la estructura es el dato en sí y si lo definimos como constante hemos de atenernos a ello.

Ahora, sin embargo, si copiamos entrada1 en una nueva variable entrada2, que sí es mutable, podremos modificar los valores de las propiedades sin problema alguno.

Structs 2

Inicializadores

No obstante, en un struct podemos crear tantos inicializadores como queramos, eso sí, todos principales o designados. No podemos usar inicializadores secundarios o de conveniencia como en las clases, aunque en este caso los inicializadores de un struct sí pueden llamarse los unos a los otros sin problema usando la referencia self.init.

Podríamos crear un nuevo inicializador como este que solo pidiera dos parámetros y establecer nosotros los otros dos, sin problema alguno. Lo realmente importante es recordar que si creamos un inicializador, el que hemos usado por defecto (el sintetizado) desaparece y tendríamos que re-crearlo nosotros en código si queremos volver a usarlo. En caso de usar nuestro propio inicializador todas las propiedades no opcionales del struct han de tener valor y no quedar vacías en cada una de las funciones init que creemos.

Como hemos comentado antes, podemos llamar de un inicializador a otro sin problema, por lo que podríamos crear el código del inicializador que hemos hecho desaparecer al poner el nuestro propio y hacer que el personalizado llame a este por defecto.

Métodos normales y de mutación

Lo que también podemos usar en un struct al igual que en una clase, son métodos. Pero en este caso hemos de tener presente algo muy importante: al ser un tipo de dato por valor no pueden modificarse sus propiedades desde un método propio al struct en sí.

Si queremos hacer un método normal que trabaje con los datos del mismo no hay problema y podemos crear cualquier función que se nos ocurra, por ejemplo esta que recupera el dominio de la dirección de email que se haya proporcionado al crear el apunte en la agenda.

Pero si queremos modificar el valor de alguna propiedad del struct desde un método del mismo, no podemos porque es un tipo de dato por valor y como tal, los datos están definidos internamente como inmutables. Externamente sí podemos modificarlos, pero lo que hace el sistema en ese caso es crear una nueva copia del dato, asignar esta y borrar la anterior: una sustitución en toda regla. Para el caso que queramos hacer esto desde dentro del struct hemos de indicar la palabra clave mutating antes de func y el nombre de la función.

De esta forma, como se ejemplifica arriba, podemos crear una función que sustituya el dominio del email por otro nuevo que indiquemos, y esto modificará la propiedad correspondiente.

Conclusión

Y esto, en esencia, son los structs. Una estructura de datos similar a una clase, pero que como hemos dicho sin herencia y en datos por valor. Los structs, igualmente, permiten usar protocolos de forma que podemos construir especificaciones que queramos que encajen con este (se conformen) y ahí es donde está la clave para la nueva orientación a protocolos que incorpora Swift 2. A partir de implementaciones por defecto y de la herencia que sí permiten los protocolos, nos permite construir un nuevo tipo de abstracción basado en datos por valor que, al final, resultan más eficientes a nivel de memoria para algunos casos en que trabajemos con Swift.

No hemos de entender que la orientación a protocolos y el uso de structs serán la solución a todos nuestros problemas para siempre y hemos de olvidarnos de la orientación a objetos: ni mucho menos. Esta es una nueva opción que viene a sumar opciones, nuevas posibilidades que nos permitan ir a más allá, ser más eficientes y poder elegir un tipo de abstracción u otra o un tipo de estructura de dato, clase o struct, en función de la pertinente conveniencia a cada caso concreto que habremos de estudiar analizando nuestra app o juego antes de siquiera de escribir una sola línea de código.

Como solemos decir: practicad, probad, experimentad y como siempre Good Apple Coding

Compra "Aprendiendo Swift 3"

Acerca de Julio César Fernández

Analista, consultor y periodista tecnológico, desarrollador, empresario, productor audiovisual, actor de doblaje e ingeniero de vídeo y audio.

Otras recomendaciones

Lecciones Prototipos (I): UITableView

Lecciones por prototipos (I): Vistas de tabla (UITableView)

Primera lección por prototipos, un nuevo e innovador contenido. A veces, lo normal es que nos perdamos sin terminar de entender qué es o cómo funcionan los componentes que forman parte de una app o un juego. Para este caso hemos creado las lecciones por prototipos. Una exploración básica de conceptos esenciales a través de prototipos en Playground que podemos probar con Swift Playgrounds en el iPad o con Xcode 8. En esta primera lección abordamos las UITableView (vistas de tabla). Un elemento esencial en la mayoría de apps de iOS que muchas veces no es entendido desde su base y por lo tanto, provoca un mal uso de las mismas.

  • Rikman

    Hola Julio quería felicitarte por tu trabajo, me está sirviendo de gran ayuda para iniciarme en swift. Espero que puedas continuar con el curso porque está muy bien.

    Un saludo y gracias!!

  • Pingback: Swift Lección 8: Protocolos | Apple Coding()

  • .[Roberto Hevens]

    sobresaliente Julio!! Te felicito un abrazo!

    Roberto