Escrito por Reinder de Vries el 10 de enero de 2019 en Desarrollo de aplicaciones, Swift

Un singleton es una clase de la que existe exactamente una instancia, a la que se puede acceder globalmente. ¿Cómo se crea un singleton en Swift? ¿Y por qué deberías o no deberías?

En este tutorial, nos sumergiremos en singletons en Swift. Aprenderás qué es el patrón de diseño único y por qué es útil. Discutiremos la sintaxis para crear singletons en Swift. Y nos meteremos en casos de uso buenos y malos para singletons.

Listo? Vamos.

  1. ¿Qué Es Un Singleton?
  2. Codificar Un Singleton En Swift
  3. Cuándo Usar Singleton
  4. Lectura Adicional

¿Qué Es Un Singleton?

Un singleton es una clase de la que solo existe una instancia. Algunos ejemplos:

  • Una empresa tiene solo un CEO
  • Una clase API tiene solo una cola de solicitud en serie
  • Un sistema operativo tiene solo un sistema de archivos
  • Un cuerpo del sistema solar gira alrededor de un punto gravitacional
  • Una aplicación que hace E/S tiene solo un sistema predeterminado FileManager
  • Un avión tiene solo una cubierta de vuelo

El segundo atributo de un singleton es que tiene un punto de acceso global. Puede acceder a un singleton, por ejemplo. funciones de llamada en él, desde cualquier lugar del código de la aplicación.

Entonces, para resumir:

  1. Un singleton es una clase que tiene una sola instancia
  2. Se puede acceder a él de forma global, es decir, en cualquier lugar de su código

En el desarrollo práctico de iOS, usa singleton a menudo. Clases típicas como NotificationCenter, UserDefaults, SKPaymentQueue y FileManager tienen propiedades shared o default que son singletones.

En otras ocasiones, es posible que desee crear un singleton usted mismo. Un buen caso de uso es una clase API que expone una instancia individual a través de su propiedad shared. Se utiliza API.shared.makeAPICall() para acceder a la API a través de una sola instancia unificada. Esto le permite, por ejemplo, administrar llamadas de API en serie.

Antes de discutir cuándo se usan mejor los singleton (y cuándo no), averigüemos cómo codificar un singleton en Swift.

Contrata como desarrollador de iOS

Aprende a crear aplicaciones de iOS 14 con Swift 5

Inscríbete en mi curso de desarrollo de iOS y aprende a comenzar tu carrera como desarrollador de iOS profesional.

Codificar un Singleton en Swift

Esta es la mejor manera de crear un singleton en Swift:

class API{ static let shared = API() private init() { // Set up API instance }}

Y así es como se usa el singleton:

API.shared.doSomething()

Estamos creando una clase API que tiene una propiedad estática llamada shared. Esta propiedad no se puede cambiar una vez establecida, porque es una constante y se declara estáticamente.

Eso significa que podemos acceder a la propiedad shareda través de la clase API. Esto a menudo se llama propiedad de clase. Compare esto con una propiedad de instancia normal, a la que solo se puede acceder a través de una instancia de una clase.

Lo interesante es que la propiedad shared inicializa una instancia de API dentro de la clase API. Estamos creando un objeto API al que se puede acceder a través de la clase API. Pero hay más

El inicializador de clases init() está marcado con private. Esta palabra clave private garantiza que la clase API solo se pueda inicializar dentro de la clase API.

En otras palabras, no puede crear una instancia de API fuera de la clase API. Esto garantiza que el objeto API que hemos creado sea la única instancia de nuestro código. Después de todo, no puedes crear más.

Y ahora nos hemos asegurado de que la clase API se ajuste a los dos atributos de un singleton:

  1. Gracias a la propiedad estática shared, se puede acceder globalmente a la instancia API
  2. Gracias a private init(), la clase API no se puede inicializar fuera de la clase API

Todo esto puede sonar un poco abstracto, así que expandamos el ejemplo anterior con un código más práctico. Esto es lo que:

La clase API es casi la misma. Sigue siendo un singleton, y todavía usa esos bits de código static let shared = API() y private init().

Esto es lo que ha cambiado:

  • La clase API ahora tiene una propiedad isRequestPending. Aquí es donde comienza el peligro See Vea cómo el booleano isRequestPending garantiza que solo se pueda realizar una solicitud de API a la vez. (Tenga en cuenta que isRequestPending es una propiedad de instancia.)
  • La clase API también tiene una función makeAPIRequest(). Imagine que podemos usar esta función para recuperar algunos datos de una API de servicio web, como la de Twitter. En la función, puede ver que solo se puede realizar una solicitud cuando no hay ninguna otra solicitud pendiente actualmente.
  • La clase API también tiene una función onReturnAPIRequest(). Esta función se invoca cuando regresa la solicitud de API, es decir, los datos en línea se han descargado en la aplicación. El booleano isRequestPending se establece de nuevo en false y se procesan los datos de la solicitud.

Y así es como podemos usar el singleton API en cualquier lugar de nuestro código:

API.shared.makeAPIRequest()

Hay algo más que tenemos que discutir. La clase API ahora administra algo llamado state. Puedes ver el «estado» como un sentimiento: eres feliz o estás triste, o estás enojado, y así sucesivamente. Puede cambiar de un estado a otro.

La clase API puede cambiar entre dos estados:

  • Un estado en el que isRequestPending es false
  • Un estado en el que isRequestPending es true

Como aprenderás en la siguiente sección, el estado y los singletons pueden causar todo tipo de estragos en tu código. Administrar mal el estado es la mayor razón para el mal uso de singleton.

Cuándo Usar monoplazas

¿Cuándo usar monoplazas? El libro Design Patterns: Elements Of Reusable Object-Oriented Software de the Gang of Four tiene lo siguiente que decir. Utilice el patrón singleton cuando:

  • debe haber exactamente una instancia de una clase, y debe ser accesible para los clientes desde un punto de acceso bien conocido
  • cuando la única instancia debe ser extensible mediante subclase, y los clientes deben poder usar una instancia extendida sin modificar su código

Eso es complejo, pero a lo que se reduce es a:

  • Use un singleton cuando su código no requiera más de una instancia de una clase (es decir, el CEO de la compañía)
  • y cuando debe ser accesible desde cualquier parte de su código (es decir, desde cualquier lugar de su código)., el sistema de archivos)

Otro caso de uso es la subclase. Una variable global en su código no puede ser fácilmente subclasificada, por lo que es por eso que usa una clase singleton. Además, los singletes se pueden probar por unidad mediante inyección de dependencias. Reemplace la instancia API por una instancia APIMock y obtenga la capacidad de realizar llamadas a la API de prueba unitaria sin realizar las solicitudes de red reales.

¿Y cuándo no utiliza monoplazas? Para responder a esa pregunta, tendremos que volver al principio de estado que discutimos anteriormente.

Un escollo común para los desarrolladores de iOS principiantes es administrar mal el estado y sus dependencias. Imagine que está creando una aplicación que utiliza la clase API con la que trabajamos anteriormente.

Cada vez que expande la clase API, agrega más y más propiedades, como:

  • Una propiedad userID que realiza un seguimiento del usuario que ha iniciado sesión, una vez que se ha realizado la llamada a la API login()
  • Una propiedad tweets con datos de Twitter, una vez que se ha realizado la llamada getTweets()
  • Una propiedad spinner con un UIActivityIndicatorView que agrega a un controlador de vista cuando se ha iniciado una solicitud

Al principio, esto tiene mucho sentido. Después de todo, se puede acceder a la clase API en cualquier parte de su código. Por lo tanto, en el Controlador de vista de Tweet puede usar la matriz API.shared.tweets, y en el Controlador de configuración puede usar userID para indicar rápidamente a la API cuya configuración debe cambiar.

Desafortunadamente, su estado ahora está en todas partes. La clase API tiene dependencias para un grupo de clases que no están relacionadas con la responsabilidad única de la clase API. Tu código se ha convertido en un plato de espaguetis, todo enredado. El código puede funcionar bien, pero es imposible de mantener y extender.

veamos un ejemplo. La función onReturnAPIRequest() que definimos anteriormente está a punto de acoplarse estrechamente

Esto es lo que estamos considerando:

  • Se llama a onReturnAPIRequest() cuando regresa una solicitud de servicio web de API, es decir, cuando los datos entran en la aplicación. Estos datos deben ir a alguna parte, por ejemplo, un Controlador de vista de Tweets. ¿Cómo pasa los datos de API al controlador de vista?
  • Una opción obvia es crear una referencia a viewController en la clase API. Cuando llegan los datos, puedes codificar algo como viewController.tweets = tweetsData. Esta es una arquitectura pobre, desafortunadamente, porque ahora API y el controlador de vista están estrechamente acoplados. Es imposible (o difícil) realizar pruebas unitarias, y es probable que cree problemas al extender cualquiera de las clases.
  • Es mejor elegir un mecanismo que no combine estrechamente ambas clases. Una opción sería pasar un cierre a onReturnAPIRequest(), que se ejecuta cuando regresa la solicitud. Este cierre puede contener código para manejar los datos entrantes. Otra opción sería usar NotificationCenter para pasar los datos al controlador de vista, o usar una clase Database para manejar los datos.

El patrón de diseño singleton ha ganado cierta controversia, simplemente porque es fácil de usar incorrectamente. Al usar singletons, tenga en cuenta el estado y las dependencias. El hecho de que sea fácil tener acceso global al estado, no significa que sea una buena idea.

Contrata como desarrollador de iOS

Aprende a crear aplicaciones de iOS 14 con Swift 5

Inscríbete en mi curso de desarrollo de iOS y aprende a comenzar tu carrera como desarrollador de iOS profesional.

Leer Más

Y eso es todo lo que hay! Conocer singletons es un objetivo que vale la pena, especialmente si está interesado en la arquitectura de aplicaciones y el diseño de sistemas.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.