SwiftUI, la nueva forma de construir apps que lo cambiará todo

SwiftUI, la nueva forma de construir apps que lo cambiará todo

29 comentarios Facebook Twitter Flipboard E-mail
SwiftUI, la nueva forma de construir apps que lo cambiará todo

Aún estamos terminando de poner en claro todo lo que hemos conocido en una de las WWDC más intensas y más cargadas de novedades que hemos tenido en los últimos años.

Pero seguro que muchos de vosotros se dieron cuenta que en los últimos 20 minutos de la presentación cambiaba el tono completamente. De una gala centrada en temas de usuario, se pasó a hablar de desarrollo puro y duro. En esta parte se presentó algo que es un primer paso revolucionario hacia el futuro del desarrollo de apps nativas en sistemas Apple: SwiftUI.

Vamos a explicarlo para que entendamos su importancia y el paso que es para Apple. Un paso que irá teniendo incidencia en las apps que usamos en el día a día en los próximos años.

Era una tranquila noche en la antigua Grecia...

Allá por el año 1979, Steve Jobs, Jef Raskin y otros cuantos afortunados ingenieros de Apple acudieron al Xerox PARC, buscando una evolución que no terminaba de llegar en el mundo de la microinformática. Los ordenadores habían comenzado a llegar a los hogares de la gente, pero que fueran una interfaz de texto con un lenguaje de programación, el BASIC en aquella época en los Apple II, no ayudaba a popularizarlos. Había que ir más allá.

Xerox Alto

En aquel viaje descubrieron el Xerox Alto, un ordenador con monitor en modo portrait que tenía una interfaz gráfica de usuario (algo que nadie había visto jamás) y un curioso aparato que controlaba una flecha llamado: ratón.

Los ingenieros de Xerox, comandados por Alan Kay, habían construido sin saberlo en un proyecto descartado y no entiendo de la compañía, el futuro de la informática. Pero no crearon solo el ordenador, porque sabían que hacer aplicaciones para una interfaz gráfica de usuario iba a ser muy complejo, así que también idearon su propio paradigma de desarrollo que revolucionaría también el mundo de la programación: el modelo MVC (model-view-controller) aplicado a la orientación a objetos.

Alan Kay es el precursor de las interfaces gráficas y la programación orientada a objetos para estas. Suya es la frase que Steve Jobs usó en la presentación del iPhone en 2007: "Aquellos que se tomen en serio el software deberían crear su propio hardware".

En 1983 Apple lanzó el Lisa y Xerox el Alto, pero su alto precio (más de $18.000) mandaron ambos productos al fracaso hasta que en 1984 llegó el Macintosh. Este hizo dos cosas bien: la primera tener un precio más asequible (en comparación, pues eran $2.495). La segunda que venía con una serie de discos con guías de aprendizaje y unas cintas de cassette (sí, sí, cintas) que ponías en tu pletina, le dabas al PLAY y oías cómo se te guiaba paso a paso sobre cómo funcionaba y se manejaba la interfaz gráfica de usuario del Macintosh y las diferentes apps que venían en disco.

Las cintas de cassette que te enseñaban a usar MacWrite y MacPaint Las cintas de cassette que te enseñaban a usar MacWrite y MacPaint

Desarrollar para ese ordenador era poco menos que un infierno. El equipo de Steve Jobs se dedicó solo a dar salida al producto, pero no a cómo crear software para ese producto. Hacer una aplicación para una interfaz gráfica se hacía programando gráficamente cada línea de cada botón, campo o elemento que se viera en pantalla: no se podía re-utilizar código, no existían las librerías (o frameworks) y cualquier elemento eran cientos o miles de líneas. Hacer que desarrollar software fuera fácil era el paso siguiente que Jobs hubiera dado tras el lanzamiento del Macintosh, pero como ya sabemos fue invitado a abandonar la empresa que co-fundó.

Así que fundó NeXT y allí aplicó el otro 50% del gran descubrimiento que hizo en el Xerox PARC: desarrollar la tecnología detrás de la creación de aplicaciones para interfaces gráficas de usuario de Alan Kay. El trabajo de todo el equipo de NeXT se lanzó en 1988 y supuso toda una revolución. Con la nueva aplicación Interface Builder y usando el lenguaje Objective-C, se podía coger un lienzo, arrastrar y soltar un botón, un campo de texto, una etiqueta, una casilla de check... cualquier elemento. Arrastrar y soltar. Luego se creaba una conexión entre el código y el elemento gráfico (un outlet) y ya podíamos trabajar con el objeto de ese elemento.

Aunque fue ideado por Alan Kay en los años 70, el desarrollo orientado a objetos para interfaces gráficas de usuario no llegó al gran público hasta 1988 con el lanzamiento de Interface Builder para el sistema operativo NeXTSTEP de los ordenadores NeXT.

No solo eso: todo funcionaba con dos librerías que NeXT lanzó con todo el código necesario para construir apps y usar esos componentes, así como librerías básicas de trabajo con cadenas, fechas o diferentes tipos de datos: las librerías AppKit y FoundationKit. Aquel fue el momento en que el desarrollo cambió para siempre y fue de nuevo Steve Jobs quien capitaneó otro cambio disruptivo en la historia de la informática. Porque tampoco existían los frameworks hasta entonces.

Interface Builder en el sistema operativo NeXTSTEP de NeXT Interface Builder en el sistema operativo NeXTSTEP de NeXT

Esta tecnología fue la responsable que Steve Jobs volviera a Apple en 1996, dado que la empresa que co-fundó se había quedado sin arquitectura de desarrollo (basada en Pascal) tras la compra por parte de Borland de la principal herramienta que se usaba para crear apps para MacOS. Y de ahí surgió en 2001 OS X y en 2007 la librería UIKit que permitió dar vida al primer iPhone.

Desde entonces nada ha cambiado en cuanto a arquitectura: podemos hacer más cosas, más rápidamente, mejor, incluso con un nuevo lenguaje como Swift. Pero la arquitectura de desarrollo, la forma en que hacemos las apps arrastrando elementos a un lienzo y creando un outlet que lo conecta al código es la misma. Los cimientos no han cambiado en más de 30 años... hasta ahora.

UIKit, interfaces imperativas

La arquitectura que se ha venido usando hasta ahora, está basada en lo que hoy se conoce como construcción de interfaces imperativas. Una construcción en la que creo una función y la asocio a un botón (por ejemplo). Creo una acción. Cuando alguien toque el botón, aquellas líneas que hay en el botón serán ejecutadas. Nada más simple.

Pero una interfaz imperativa tiene un problema que la hace menos eficiente: lo que llamamos el "estado". Básicamente aquellos valores que tenemos en nuestro código y que cuando tocamos deben tener un reflejo en lo que hemos tocado. Si yo pulso el botón, recibo una variable (un dato) que es el propio botón. Y a este, por ejemplo, le puedo cambiar el color o su texto por haber sido pulsado. Al cambiar esa propiedad de esa variable que es el botón, la interfaz tiene que reaccionar de forma inmediata y cambiar dicho color o texto. Estamos cambiando su "estado".

Xcode 10

Cada posible valor que yo pueda darle a un elemento en la interfaz es un estado. Si tengo un campo que puede estar activo o no, tengo una propiedad de tipo Bool que será verdadera o falsa (solo tiene esos dos posibles valores). Verdadero está activo, falso no lo está. Dos estados. Pero también tengo otro propiedad de tipo Bool que es si el campo está o no oculto. Ya tengo cuatro posibles estados que gestionar desde la interfaz:

  • Oculto sí, activo sí
  • Oculto no, activo sí
  • Oculto sí, activo no
  • Oculto no, activo no

Cualquier elemento de la interfaz tiene cientos más de posibles estados para cada elemento: color, texto, color del borde, sombra, se toca o no... muchísimos. La complejidad es enorme y a mayor complejidad, más le cuesta a un sistema gestionar una interfaz llena de elementos. Básicamente porque tiene que estar "atento" a todos estos posibles cambios de estado y combinaciones para reaccionar ante ellos. Algo poco eficiente y muy propenso a errores.

Una interfaz imperativa debe estar atenta al cambio de cualquier estado, y las combinaciones entre tantos elementos pueden ser millones de posibles diferentes estados a representar.

La respuesta para hacer más eficientes a las interfaces llegó en los años 90 cuando se comenzaron a usar lenguajes de maquetación como el HTML, donde tenemos un ejemplo perfecto de interfaz declarativa. Una interfaz que se define como es y no cambia hasta que el usuario interactúa y se cambia a otra página. Pero la página HTML en sí, mientras la vemos, no cambia nunca. Es inmutable.

SwiftUI, interfaces declarativas

Obviamente, usar una interfaz declarativa como HTML, completamente inmutable, es poco práctico. Así que los desarrolladores se pusieron a trabajar para encontrar formas de trabajar con el estado, pero que cualquier posible cambio en este también estuviera declarado con anticipación. De esta forma, si un estado cambia por la interacción de un usuario, la interfaz sabrá qué tiene que hacer pero no lo cambiaremos nosotros con ningún código. Nosotros ya le dijimos qué tenía que pasar cuando la declaramos.

SwiftUI

Vamos a verlo aún más claro: si la interfaz no sabe qué puede pasar con ella, tiene que estar pendiente de forma constante a millones de combinaciones de posibles cambios. Son un montón de observadores que están esperando eventos: que cambie un color, que se mueva un campo, que cambie un tipo de letra, que se mueva una imagen... todos los posibles cambios que puede tener una interfaz (todos sus posibles cambios de estado) están en permanente escucha y la interfaz tiene que estar preparada para representarlos.

Pero si hago una interfaz declarativa, yo estoy definiendo (antes que se pinte esta) qué estados tiene que observar y qué tiene que hacer cuando ocurra. Solo tendrá que estar pendiente de estos porque todo lo demás será inmutable. E incluso podrá procesar anticipadamente todas las combinaciones. Así que el coste de proceso de gestionar esa interfaz de usuario es infinitamente menor. Porque ya estamos declarando al construir la interfaz qué puede hacer y qué no: todas sus reglas. Así que solo tiene que estar atenta a estas, cumplirlas y sabe antes de ejecutarlos cuántas combinaciones posibles tendrá esa interfaz. Nada más.

SwiftUI

Hoy día muchas librerías como Flutter de Google o React de Facebook, ya usan interfaces declarativas, y ahora Apple se ha subido al carro de esta tendencia en el desarrollo, de la mano de su lenguaje Swift con SwiftUI.

Gracias a SwiftUI, además, veremos la correspondencia en tiempo real entre nuestro código que declara la interfaz y su resultado. Usando sus diferentes componentes, esta interfaz se construirá y dibujará de forma automática para iPhone, iPad, macOS, watchOS y tvOS. Adiós a las temidas constraints, reglas que había que dar para que nuestra interfaz fuera capaz de dibujarse en cualquier dispositivo fuera cual fuera su tamaño. Ahora todo ello lo controla de forma automática el sistema como lo haría un navegador con HTML.

SwiftUI es el paso que da Apple de sumarse a las tendencias que otros como Google o Facebook ya hicieron, creando sus propias librerías de construcción de interfaces declarativas como Flutter o React.

Por supuesto, tenemos las suficientes propiedades para usar, que nos permitan dibujar lo que queramos sin problema, animaciones incluidas, fuentes de datos dinámicos asociados a la interfaz, eventos... todo lo necesario.

Un pequeño ejemplo de estructura

Cuando creamos un nuevo proyecto en Xcode 11, lo primero que vemos es un nuevo check que nos dice si queremos crear un proyecto con SwiftUI y esto nos crea un proyecto con un nuevo delegado de escenas (que se usará, entre otros cosas, para la nueva función de múltiples copias de una misma app abiertas al mismo tiempo), pero no tendremos como es costumbre un Storyboard de inicio donde normalmente empezamos a crear nuestra interfaz.

Interfaz compleja en SwiftUI

En su lugar hay un fichero llamado ContentView que desde la escena es usado para generar la pantalla de inicio con código. El funcionamiento, sin entrar en mucho detalle técnico, se basa en un struct de Swift (una estructura) a la que le digo que es de tipo View. Esto obliga a que se incluya una variable Body que devolverá los diferentes constructores: el cuerpo de la pantalla.

struct ContentView : View {
  var body: some View {
   Text("Hello World")
  }
}

Lo que hay dentro de body es un constructor que crea un texto y lo pone justo en el centro de la pantalla. Así de simple. Si quiero que el texto sea en negrita, pongo un punto después del paréntesis y llamo a la función bold().

Text("Hello World").bold()

La interfaz que hemos dibujado

Si quiero meter más de un elemento tengo que usar agrupaciones, como un vista apilada. Con Vstack creo una y pongo dentro lo que quiero.

struct ContentView : View {
 var body: some View {
   VStack {
     Text("Hello World").bold()
     Image(systemName: "book")
   }
  }
}

De esta forma pongo un vista apilada vertical con el texto encima y una imagen del nuevo conjunto de caracteres San Francisco Symbols, que representa un libro. Ahora le pongo un botón.

struct ContentView : View {
   var body: some View {
     VStack {
       Text("Hello World").bold()
       Image(systemName: "book")
       Button(action: {
         print("Toqué")
       }, label: {
         Text("Soy un botón")
       })
     }
   }
}

Aquí le digo que quiero un botón y le paso dos parámetros como bloques de código (o closures): action que es lo que hará al pulsarse el botón y label que es aquello que se mostrará en el botón, un texto. Podría haber mandado una imagen y se hubiera hecho un botón de una imagen.

Esto es lo más simple y sencillo, obviamente. Solo un pequeño atisbo de todas las posibilidades que hay a la hora de construir interfaces. Si usamos macOS Catalina, podremos ver el lienzo al lado del código y añadir elementos arrastrando y soltando en la interfaz, viendo cómo queda y cualquier cambio en dicho constructor modificará el código en tiempo real. Igual que cualquier cambio en el código, cambia la interfaz al momento.

Un primer paso

Esta tecnología es un paso adelante sin precedentes, que ahora mismo funciona como una librería nativa en Swift que saca todo la ventaja del lenguaje y sus características, que se unen a otra librería de programación reactiva (para eventos asíncronos) llamada Combine de la que hablaremos más adelante si os interesa.

Pero ojo, hay que ser realista. Crear una librería de construcción de interfaces desde 0 es una tarea épica, y Apple solo acaba de empezar y nos deja comenzar a usar y aprender (porque hemos de aprender casi desde 0) una nueva forma de hacer interfaces. Pero ahora mismo funciona como una capa puesta encima del anterior UIKit, no es independiente a nivel infraestructura. ¿Siempre será así? No, Apple irá independizando el motor. El mismo lenguaje Swift siguió ese proceso: en la primera versión Swift era una forma diferente de escribir Objective-C, que se traducía a este en muchos elementos y tipos de datos. Y ahora es completamente independiente en su arquitectura.

SwiftUI es un primer paso, que ahora mismo funciona por encima de UIKit y no como una librería independiente. Pero al igual que Swift, que al principio en gran parte era una traducción de Objective-C y ahora es un lenguaje independiente, SwiftUI tiene que dar más pasos en el futuro.

Estamos seguros que lo que ahora es una capa de la antigua librería UIKit, pero que permite una forma diferente y más práctica de hacer apps, pasará poco a poco a ir consiguiendo su propia arquitectura independiente, hasta serlo completamente de UIKit y crear una nueva librería que no olvidemos es compatible con todos los sistemas Apple.

Tal como pasó con Swift cuando fue lanzado en 2014, estamos echando un vistazo al futuro y ya podemos empezar a trabajar con él. Y volvemos a lo de siempre: Apple no ha inventado nada, todo esto ya estaba inventado. Pero ellos crean su propia versión con un objetivo claro: ser los que mejor lo hacen. Por ahora, parece que van por buen camino.

Comentarios cerrados
Inicio