Introducción a Combine en Swift
Introducción a Combine en Swift

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!

SwiftBeta

Tabla de contenido


👇 SÍGUEME PARA APRENDER SWIFTUI, SWIFT, XCODE, etc 👇

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.
Aprende desde cero Combine en Swift
Aprende desde cero Combine en Swift

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:

let myArray = ["1", "2" ,"3" ,"4"]
Array de Strings en Swift

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.

Podemos crear Publishers directamente de un Array en Swift
Podemos crear Publishers directamente de un Array en Swift

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:

let myArray = ["1", "2" ,"3" ,"4"]
let myPublisher = myArray.publisher
Creamos un publisher a partir de un Array de Strings en Swift

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:

let just = Just(["1", "2" ,"3" ,"4"])
Otra manera de crear un Publishe es 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:

myPublisher.sink { isFinished in
    print("isFinished: \(isFinished)")
} receiveValue: { value in
    print("Value Received: \(value)")
}
Primera vez que nos suscribimos a un Publisher usando combine

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:

Value Received: 1
Value Received: 2
Value Received: 3
Value Received: 4
isFinished: finished
Resultado obtenido 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.

let justInteger = Just(2222)
let swiftBetaChannel = YoutubeChannel()
justInteger.assign(to: \YoutubeChannel.numberOfSuscribers, on: swiftBetaChannel)
print(justInteger)
Podemos suscribirnos usando assignTo a un Publisher en Combine

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.