Écrit par Reinder de Vries le 10 janvier 2019 dans Développement d’applications, Swift

Un singleton est une classe dont il existe exactement une instance, accessible globalement. Comment créer un singleton dans Swift? Et pourquoi devriez-vous ou ne devriez-vous pas?

Dans ce tutoriel, nous allons plonger dans les singletons dans Swift. Vous apprendrez ce qu’est le modèle de conception singleton et pourquoi il est utile. Nous discuterons de la syntaxe pour créer des singletons dans Swift. Et nous entrerons dans de bons et de mauvais cas d’utilisation pour les singletons.

Prêt? Allons-y.

  1. Qu’Est-Ce Qu’Un Singleton ?
  2. Coder Un Singleton Dans Swift
  3. Quand Utiliser Des Singletons
  4. Lecture Ultérieure

Qu’Est-Ce Qu’Un Singleton?

Un singleton est une classe dont une seule instance existe. Quelques exemples:

  • Une entreprise n’a qu’un seul CEO
  • Une classe API n’a qu’une file d’attente de requêtes série
  • Un système d’exploitation n’a qu’un seul système de fichiers
  • Un corps du système solaire tourne autour d’un point gravitationnel
  • Une application qui effectue des E/S n’a qu’un seul système par défaut FileManager
  • Un avion n’a qu’un seul poste de pilotage

Le deuxième attribut d’un singleton est qu’il a un point d’accès global. Vous pouvez accéder à un singleton, par exemple. fonctions d’appel dessus, de n’importe où dans le code de votre application.

Donc, pour résumer:

  1. Un singleton est une classe qui n’a qu’une seule instance
  2. Elle est accessible globalement, c’est-à-dire n’importe où dans votre code

Dans le développement pratique d’iOS, vous utilisez souvent des singletons. Des classes typiques comme NotificationCenter, UserDefaults, SKPaymentQueue et FileManager ont des propriétés shared ou default qui sont des singletons.

À d’autres moments, vous pouvez créer vous-même un singleton. Un bon cas d’utilisation est une classe API qui expose l’instance singleton via sa propriété shared. Vous utilisez API.shared.makeAPICall() pour accéder à l’API via une seule instance unifiée. Cela vous permet, par exemple, de gérer les appels d’API en série.

Avant de discuter du moment où les singletons sont les mieux utilisés (et quand ce n’est pas le cas), voyons comment coder un singleton dans Swift.

Soyez embauché en tant que développeur iOS

Apprenez à créer des applications iOS 14 avec Swift 5

Inscrivez-vous à mon cours de développement iOS et apprenez à démarrer votre carrière en tant que développeur iOS professionnel.

Coder Un Singleton Dans Swift

C’est la meilleure façon de créer un singleton dans Swift:

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

Et voici comment vous utilisez le singleton:

API.shared.doSomething()

Nous créons une classe API qui a une propriété statique appelée shared. Cette propriété ne peut pas être modifiée une fois définie, car c’est une constante et elle est déclarée statiquement.

Cela signifie que nous pouvons accéder à la propriété shared via la classe API. C’est souvent ce qu’on appelle une propriété de classe. Comparez cela à une propriété d’instance normale, accessible uniquement via une instance d’une classe.

Ce qui est intéressant, c’est que la propriété shared initialise une instance de API dans la classe API. Nous créons en quelque sorte un objet API accessible via la classe API. Mais il y a plus…

L’initialiseur de classe init() est marqué par private. Ce mot-clé private garantit que la classe API ne peut être initialisée que dans la classe API.

En d’autres termes, vous ne pouvez pas créer une instance de API en dehors de la classe API ! Cela garantit que l’objet API que nous avons créé est la seule instance de notre code. Après tout, vous ne pouvez pas en créer plus.

Et maintenant nous nous sommes assurés que la classe API est conforme aux deux attributs d’un singleton:

  1. Grâce à la propriété statique shared, l’instance API est accessible globalement
  2. Grâce à la private init(), la classe API ne peut pas être initialisée en dehors de la classe API

Tout cela peut vous sembler un peu abstrait, alors développons l’exemple précédent avec un code plus pratique. Voici quoi:

La classe API est généralement la même. C’est toujours un singleton, et il utilise toujours ces bits de code static let shared = API() et private init().

Voici ce qui a changé:

  • La classe API a maintenant une propriété isRequestPending. C’est là que le danger commence See Voyez comment le booléen isRequestPending garantit qu’une seule demande d’API peut être effectuée à la fois ? (Notez que isRequestPending est une propriété d’instance.)
  • La classe API a également une fonction makeAPIRequest(). Imaginez que nous puissions utiliser cette fonction pour récupérer des données d’une API de service Web, comme celle de Twitter. Dans la fonction, vous pouvez voir qu’une demande ne peut être faite que lorsqu’aucune autre demande n’est actuellement en attente.
  • La classe API a également une fonction onReturnAPIRequest(). Cette fonction est appelée lorsque la demande d’API revient, c’est-à-dire que les données en ligne ont été téléchargées dans l’application. Le booléen isRequestPending est à nouveau défini sur false et les données de requête sont traitées.

Et voici comment nous pouvons utiliser le singleton API n’importe où dans notre code:

API.shared.makeAPIRequest()

Il y a autre chose dont nous devons discuter. La classe API gère maintenant quelque chose appelé state. Vous pouvez voir « état » comme un sentiment: soit vous êtes heureux, soit vous êtes triste, soit vous êtes en colère, etc. Vous pouvez passer d’un état à l’autre.

La classe API peut basculer entre deux états:

  • Un état dans lequel isRequestPending est false
  • Un état dans lequel isRequestPending est true

Comme vous l’apprendrez dans la section suivante, l’état et les singletons peuvent faire toutes sortes de ravages sur votre code. La mauvaise gestion de l’état est la principale raison de l’utilisation abusive de singleton.

Quand utiliser des Singletons

Quand utilisez-vous des singletons? Le livre Design Patterns: Elements Of Reusable Object-Oriented Software par la Bande des Quatre a ce qui suit à dire. Utilisez le motif singleton lorsque:

  • il doit y avoir exactement une instance d’une classe, et elle doit être accessible aux clients à partir d’un point d’accès bien connu
  • lorsque la seule instance doit être extensible par sous-classe, et les clients doivent pouvoir utiliser une instance étendue sans modifier leur code

C’est complexe, mais ce que cela se résume à:

  • Utilisez un singleton lorsque votre code ne nécessite pas plus d’une instance d’une classe (c’est-à-dire le PDG de l’entreprise)
  • Et lorsqu’il doit être accessible de n’importe où dans votre code (c’est-à-dire, le système de fichiers)

Un autre cas d’utilisation est le sous-classement. Une variable globale dans votre code ne peut pas être facilement sous-classée, c’est pourquoi vous utilisez une classe singleton. De plus, les singletons peuvent être testés à l’unité en utilisant l’injection de dépendance. Vous remplacez l’instance API par une instance APIMock et vous avez la possibilité de tester des appels d’API unitaires sans effectuer les demandes réseau réelles.

Et quand n’utilisez-vous pas de singletons? Pour répondre à cette question, nous devrons revenir au principe de l’État dont nous avons parlé plus tôt.

Un écueil commun pour les développeurs iOS débutants est de mal gérer l’état et ses dépendances. Imaginez que vous construisez une application qui utilise la classe API avec laquelle nous avons travaillé plus tôt.

Chaque fois que vous développez la classe API, vous utilisez de plus en plus de propriétés, telles que:

  • Une propriété userID qui garde la trace de l’utilisateur connecté, une fois que l’appel d’API login() a été effectué
  • Une propriété tweets avec des données Twitter, une fois que l’appel getTweets() a été effectué
  • Une propriété spinner avec un UIActivityIndicatorView que vous ajoutez à un contrôleur de vue lorsqu’une requête a démarré

Au début, cela a beaucoup de sens à faire. Après tout, la classe API est accessible n’importe où dans votre code. Ainsi, dans le Contrôleur de vue de Tweet, vous pouvez utiliser le tableau API.shared.tweets, et dans le contrôleur de paramètres, vous pouvez utiliser userID pour indiquer rapidement à l’API dont les paramètres doivent être modifiés.

Malheureusement, votre état est maintenant partout. La classe API a des dépendances à un groupe de classes qui ne sont pas liées à la responsabilité unique de la classe API. Votre code est devenu un bol de spaghettis, tout emmêlé. Le code peut fonctionner CORRECTEMENT, mais il est impossible de le maintenir et de l’étendre.

Regardons un exemple. La fonction onReturnAPIRequest() que nous avons définie précédemment est sur le point de devenir étroitement couplée

Voici ce que nous envisageons:

  • Le onReturnAPIRequest() est appelé lorsqu’une demande de service Web API revient, c’est-à-dire lorsque des données entrent dans l’application. Ces données doivent aller quelque part – un contrôleur de vue de Tweet par exemple. Comment transmettez-vous les données du API au contrôleur de vue?
  • Un choix évident consiste simplement à créer une référence à la viewController dans la classe API. Lorsque les données entrent, vous pouvez coder quelque chose comme viewController.tweets = tweetsData. C’est une architecture médiocre, malheureusement, car maintenant le API et le contrôleur de vue sont étroitement couplés. Il est impossible (ou difficile) de tester l’unité et risque de créer des problèmes lors de l’extension de l’une ou l’autre classe.
  • Il est préférable de choisir un mécanisme qui ne couple pas étroitement les deux classes. Une option serait de passer une fermeture à onReturnAPIRequest(), qui est exécutée lorsque la requête revient. Cette fermeture peut alors contenir du code pour gérer les données entrantes. Une autre option consisterait à utiliser NotificationCenter pour transmettre les données au contrôleur de vue, ou à utiliser une classe Database pour gérer les données.

Le modèle de conception singleton a suscité une certaine controverse, tout simplement parce qu’il est facile à utiliser. Lorsque vous utilisez des singletons, soyez conscient de l’état et des dépendances. Ce n’est pas parce qu’il est facile d’avoir un accès mondial à l’État que c’est une bonne idée.

Soyez embauché en tant que développeur iOS

Apprenez à créer des applications iOS 14 avec Swift 5

Inscrivez-vous à mon cours de développement iOS et apprenez à démarrer votre carrière en tant que développeur iOS professionnel.

Pour en savoir plus

Et c’est tout ce qu’il y a à faire! Apprendre à connaître singletons est un objectif valable, surtout si vous êtes intéressé par l’architecture d’applications et la conception de systèmes.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.