Inversión de control en vistas declarativas de aplicaciones móviles: Jetpack Compose y SwiftUI

Yair Carreno
4 min readApr 26, 2022

--

Costumbres cafeteras. Taken by Hayder Londoño.

En aplicaciones móviles, los recientes frameworks Jetpack Compose y SwiftUI permiten la creación de vistas declarativas a través de lenguajes de programación de aspecto funcional tales como Kotlin y Swift respectivamente.

Estos lenguajes habilitan de forma natural la opción de otro mecanismo para aplicar el principio de inversión de control, el cual se fundamenta en un concepto que en programación funcional es conocido como “Higher order functions”.

Recomiendo al lector repasar los conceptos relacionados a inversión de control (IoC) en este otro artículo antes de continuar.

En lenguajes de programación como Kotlin o Swift, en donde las funciones son first-class, las funciones pueden recibir como parámetro una función y devolver como resultado una función. Funciones de este tipo son las denominadas como “Higher order functions”.

Veamos cómo este tipo de funciones son aplicadas en Swift y Kotlin con un par de sencillos ejemplos en Playground.

En Swift

Tenemos definidas dos tipos de operaciones (operationA, operationB) y cada una realiza una implementación diferente.

Por otro lado, tenemos una función llamada calculate que recibe un valor de tipo Double y una función que recibe un valor de tipo Double y retorna un valor de tipo Double.

Al ejecutar las sentencias tenemos como resultado: 4.0 y 6.0

En cada caso, el resultado dependerá de la función delegada para ejecutar la lógica y el dato entregado por parámetro.

La única tarea que realiza la función calculate es imprimir el resultado de aplicar la función que recibe como parámetro (operationA o operationB) al valor (data) que también recibe por parámetro. De tal forma que el algoritmo de la operación queda delegado a las funciones llamadas operationOne y operationTwo dejando desacoplada la operación de la función calculate.

¿En dónde se aplica la inversión de control?

Es claro que al permitir que una función acepte como parámetro otra función, se habilita la posibilidad de delegar la lógica o algoritmo a otro componente.

Adicionalmente, ayuda el poder usar expresiones lambdas o closures para estos propósitos y tener un código limpio y legible.

En Kotlin

En Kotlin la situación es la misma, al definir dos operaciones llamadas operationA y operationB y una función llamada calculate y de tipo higher order functions así:

Nuevamente como en el ejemplo anterior, el resultado es el mismo: 4.0 y 6.0

¿Y cuál es la novedad de este concepto con respecto a las vistas declarativas?

La novedad está en que las vistas declarativas tanto iOS como Android puede recurrir a a este concepto para aplicar un patrón de diseño llamado State hoisting.

State hoisting, es un patrón de diseño que busca liberar a una vista de responsabilidades para delegarlas a otra vista de orden superior, es decir a una vista que sea capaz de contener otras vistas, algo así como una “Higher order view”. Las ventajas de este patrón de diseño se describen más adelante.

Para entender cómo funciona en SwiftUI y en Jetpack Compose, veamos las siguientes implementaciones.

En SwiftUI

He definido una vista llamada ClickCounterView que contiene un texto y un botón. Dicha vista es a la vez una sub-vista de otra vista llamada ContentView.

¿Qué vista es la dueña de la lógica o algoritmo de la operación al dar click sobre el botón “Click me”?

La vista padre, es decir, ContentView.

Podría haberse dejado la lógica o algoritmo definido en la vista hija, es decir, en ClickCounterView, sin embargo, al delegarle la responsabilidad a la vista padre, ClickCounterView se convierte en una vista stateless (sin estado) con las siguientes ventajas:

  • Evita side-effects (efectos colaterales) al ser una vista funcional que no maneja estados.
  • Puede ser reutiliza por otras vistas o componentes.
  • Delega la tarea de ser source of truth (generadora de cambios de estados).

Estas ventajas descritas y el mecanismo usado, es lo que se conoce como State hoisting.

Simulación del ejemplo en SwiftUI.

En Jetpack Compose

En Jetpack Compose, el escenario descrito anteriormente es similar en la siguiente implementación.

En este caso la vista padre o contenedora es llamada Surface (es una vista de tipo Composable) y la sub-vista es llamada ClickCounter que también es de tipo Composable que recibe un valor y una función.

Simulación de ejemplo con Jetpack Compose.

Para concluir

Las herramientas así cómo los lenguajes evolucionan y consigo introducen una cantidad de opciones para aplicar practicas efectivas a la hora de diseñar e implementar los componentes, en este caso, vistas de aplicaciones móviles.

Sea que el lector esté familiarizado o no con estos frameworks declarativos de soluciones móviles nativas, estoy seguro que tan solo el concepto, le aportará conocimientos sobre como invertir las dependencias entre elementos, y aplicarlo en otros tipos de componentes que no sean necesariamente componentes tipo Vistas.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Yair Carreno
Yair Carreno

Written by Yair Carreno

Software engineer with a technical blog about #iOS, #Android, #Angular. Author of “The Clean Way to Use Rx”: https://leanpub.com/the-clean-way-to-use-rx

No responses yet

Write a response