Introducción a Combine (Publishers, Subscribers y AnyCancellable)
Combine es un framework que Apple publicó en 2019. Es un framework para programar nuestra app de forma reactiva pudiendo trabajar con eventos asíncronos. Hasta ahora en SwiftBeta habíamos visto callbacks, y delegation pattern. A partir de ahora tenemos nueva serie muy interesante!
Tabla de contenido
Hoy en SwiftBeta vamos a ver una introducción a Combine. Combine es un framework con una API para procesar valores a lo largo del tiempo, estos valores pueden representar diferentes eventos asíncronos. Hasta ahora, en el canal para trabajar con eventos asícronos hemos utilizado entre otros los callbacks y el patrón delegation. Estos métodos los usábamos para hacer una petición HTTP, parsear el JSON a un modelo y actualizar la UI de nuestra app. Pero hoy vamos a ver una nueva manera usando el framework Combine, al usar Combine creamos Pipelines, Tuberías por donde viajaran nuestros valores, es decir, la información que queramos transportar. Incluso podríamos simplificarlo y decir que creamos un camino, un canal por el que enviaremos información.
Si has visto los videos de SwiftUI, cada vez que utilizábamos un property wrapper como @Published por debajo, lo que está usando es el framework Combine. Pero Apple, lo hace muy fácil y es totalmente transparente para nosotros.
Tal y como te comentaba, en Combine creamos un camino, pipeline, tubería, da igual como lo llames, lo importante es que sepas que a través de esta tubería enviaremos valores a lo largo del tiempo. Pues bien, para hacer esto necesitamos un componente imprescindible en Combine llamado Publisher. Los Publishers publican información en nuestra tubería. Tener solo Publishers no nos serviría de mucho y es por eso que para poder escuchar y obtener la información que publican los Publishers, necesitamos otro componente clave llamado Subscriber, y lo que hace un subscriber es suscribirse a la información que envía el Publisher. Es decir, tenemos una tubería, donde publicamos información y todos aquellos que estén suscritos (aquellos que estén escuchando) podrán obtener los valores que viajan en nuestra tubería. Esta sería la idea principal de Combine bastante simplificada.
Al hablar de combine, entran en juego varios conceptos clave: Publishers, Subscribers y operadores. Hoy nos vamos a centrar en los dos primeros.
Para darte un poco más de contexto, este framework lo publicó Apple en 2019 y desde entonces que podemos usarlo en nuestras apps. Algunas clases de Apple tienen extensiones para que podamos usar Combine como: Timer, URLSession, NotificationCenter, incluso hoy veremos un ejemplo de algunos tipos de la librería standard de Swift que pueden crear publishers solo llamando a una propidad 🤩. La verdad que es bastante potente. Vamos a empezar por el principio.
Pero antes, si quieres apoyar el contenido que subo cada semana, suscríbete. De esta manera seguiré publicando contenido completamente grautito en Youtube.
Creamos Playground en Xcode
Nos vamos a Xcode y creamos un Playground, vamos a crear nuestro primer Publisher y para que veas lo integrado que está en la librería standard de Swift vamos a escribir un Array de Strings:
Publishers
Una vez lo hemos creado, podemos usar una propiedad llamada publisher para que todos los elementos del Array se publiquen cuando un subscriber se suscriba a nuestro publisher.
Muy sencillo! Acabamos de crear nuestro primer Publisher. Fíjate que el tipo de nuestro Publisher es Publishers.Sequence<[String], Never>. Vamos a verlo por partes.
- El primer tipo es Array de Strings, y es el tipo de valor que se publicará en nuestro Publisher.
- El segundo tipo es el tipo de Error. Es importante que sepas que un Publisher puede publicar errores. Justo en este ejemplo, el tipo de nuestro error es Never, y esto significa que nuestro Publisher no puede publicar errores, por lo tanto, no podremos enviar errores a través de nuestro Publisher, es decir, nuestro Publisher siempre finalizará de enviar todos sus eventos de manera correcta.
Lo importante es que entiendas que un Publisher define como son producidos sus valores y errores. Siempre que creamos un publisher definimos un Output y un Failure. El output es el tipo que envía el Publisher y el Failure es el tipo de error que envía el Publisher.
Vamos a asignar el publisher que acabamos de crear a una constante llamada myPublisher:
Como detalle curioso, y ya que no me puedo esperar a los siguientes videos, te comento otra manera de crear un Publisher. Hemos visto como crear un publisher usando .publisher, pero hay más maneras. Podríamos crear un publisher usando Just:
Si miramos el tipo, podemos ver que es de tipo Just<[String]> (y fíjate que curioso que no tiene ningún tipo que defina su error). Entraremos en detalle sobre Just y Promesas en otro video, pero es importante que sepas que hay otras maneras de crear Publishers en Combine.
Antes de ir a los subscribers, el otro pilar en el que se basa Combine, te comento que puedes crear tus propios Publishers con CurrentValueSubject y PassthroughSubject (que también lo veremos por el canal en los próximos videos)
Vamos a continuar.
Subscribers
Una vez hemos creado nuestro primer publisher, ahora necesitamos poder suscribirnos para recibir todos los valores que se vayan publicando. Es muy importante saber que al suscribirnos, estamos activando que el publisher pueda publicar valores. Esto se conoce como backpressure.
Hay varias maneras de suscribirnos a un Publisher, vamos a usar el método sink, y es tan sencillo como usar este método en nuestra constante myPublisher que hemos creado hace un momento:
Podemos usar el método sink con dos closures:
- El primer closure se llamará solo una vez, y será cuando hallamos recibido todos los valores de nuestro Array
- El segundo closure se llamará tantas veces como valores tengamos en nuestro Array
Dentro de nuestro Playgrond vamos a compilar, veamos qué resultado se muestra por consola:
Al suscribirnos, se han ido publicando los valores de nuestro Array. Y ha medida que han ido llegando, hemos printado su valor por consola. Una vez se ha completado el envío, se ha mostrado el print del primer closure. Indicando que ya no hay más valores por recibir.
Al suscribirnos usando sink, tenemos mucho margen para crear nuestra propia lógica dentro de los closures de completion y el closure donde vamos recibiendo valores. PERO, si quieremos asignar directamente un único valor, a algún elemento visual de nuestra UI, o alguna clase como veremos en el siguiente código, podemos usar assignTo. Esta es otra manera de suscribirse a un Publisher.
Acabamos de aprender sobre Publishers y Suscribers, pero cuál es el ciclo de vida de un Publisher? podemos parar de recibir valores? La respuesta es que sí
Al usar sink o assignTo, estos método retornan un tipo llamado AnyCancellable, este tipo es muy útil e importante dentro del framework Combine, y sirve para cancelar una suscripción. Es decir, utilizamos AnyCancellable para cancelar la suscripción de un subscriber ANTES de que haya acabado de publicar todos sus valores. Esto es muy útil para no consumer recursos cuando ya no los necesitamos. Lo veremos muy amenudo en los siguientes videos.
Te estoy mostrando muchos términos nuevos para que te vayas acostumbrando a los componentes básicos de Combine. En el próximo video vamos a hablar sobre los operadores. Hay una barbaridad de ellos y nos permiten hacer una lógica muy simple dentro de nuestras apps si los aplicamos correctamente.
Conclusión
Hoy hemos visto 2 conceptos básicos de Combine. El primero de todos han sido los Publishers, que nos permiten publicar eventos. Un Publisher puede finalizar sus publicaciones debido a 3 factores:
- Se ha completado
- Ha habido un error
- Se ha cancelado la suscripción
Los valores que se publican son interceptados por el otro pilar de Combine, que son los subscribers. Los suscribers reciben notificaciones por cada valor recibido y también cuando el Publisher ha completado de enviar todos los valores.