Différentes façons d’utiliser la classe Observer
Si vous travaillez avec la programmation orientée objet, vous connaissez certainement (ou du moins avez déjà entendu parler) du Observer
design pattern.
Ce motif se compose d’un Observable
classe qui émet events
avec personnalisé data
attaché à celle-ci. Les autres classes qui y souscrivent peuvent recevoir une notification lorsqu’un événement spécifique est déclenché.
Ce modèle est important pour l’environnement iOS et est utilisé dans les API, telles que NSNotificationCenter
,Combine
et RxSwift
. Les observable
classe émet des événements qui peuvent être déclenchés en interne ou en externe. Pour écouter les changements, le Observer
les classes doivent s’inscrire pour recevoir des notifications.
Je comprends que s’appuyer sur un modèle complexe comme Observer
peut être « tuer une abeille avec un canon ». Par exemple, vous pouvez envoyer une mise à jour à partir d’un ViewModel
à la ViewController
via NotificationCenter
. Mais le principal avantage de cela est de créer une classe qui diffuse un événement à toute autre classe intéressée par cet événement sans savoir qui peut être notifié.
Disons que nous avons un ViewController
avec un UIButton
. Lorsque ce bouton est cliqué, nous voulons que plusieurs endroits de l’application soient notifiés et mettent à jour l’interface utilisateur en affichant une bannière ou autre chose. Vous pouvez également informer plusieurs classes d’un événement réseau. Peu importe comment c’est géré, mais c’est comme Netflix — nous diffusons des notifications sur une nouvelle série sans savoir qui les recevra/combien les recevront.
C’est l’idée de Observers
. Quelques-uns ou des millions peuvent avoir besoin d’être informés de l’événement d’une seule classe.
Mais quelle est la magie derrière cela ? Comment notifions-nous beaucoup observer
s sans délai? C’est à cela que sert cet article. Nous mettrons en œuvre notre propre coutume NotificationCenter
pour enregistrer une collection d’événements et d’observateurs différents mais liés. Cela fera en sorte qu’à tout moment notre NotificationCenter
reçoit un événement avec des données jointes, nous pouvons le diffuser à plusieurs endroits. Commençons.
Deux entités centrales du projet communiquent selon le même modèle. Il y a un Observable
entité qui émet des événements avec des données attachées génériques et permet plusieurs Observers
pour écouter les événements à partir de là. Trois actions possibles peuvent être déléguées au Observable
:
notify
: raconte leNotificationCenter
pour diffuser des messages avec des données connexesregister
: raconte leNotificationCenter
enregistrer un nouveauObserver
pour recevoir des notifications concernant certains événementsunregister
: raconte leNotificationCenter
désinscrire certainsObserver
instance, afin qu’il ne reçoive aucune autre notification concernant un événement
Maintenant que nous avons nos protocoles pour établir la relation Observable-Observer
nous devrions implémenter notre classe de base pour le CustomNotificationCenter
:
Nous avons mis en place le NotificationCenter
en tant que Singleton car nous voulons un réseau central et unique pour diffuser des messages dans toutes les parties de notre application. Il s’agit d’un cas d’utilisation classique pour le modèle de conception Singleton, car nous ne souhaitons pas plusieurs instances pour NotificationCenter
. Nous avons donc une déclaration shared
instance qui ne peut être instanciée qu’une seule fois en raison de la propriété privée init
. Nous avons également déclaré les trois fonctions dans notre protocole.
Maintenant que nous avons notre NotificationCenter
class, nous sommes prêts à implémenter notre structure de données pour enregistrer les événements possibles et les observateurs qui s’abonnent à chaque événement. Avant de déclarer le observer
s, réfléchissons à la meilleure façon de sauvegarder ce genre de données afin qu’elles puissent être diffusées à tous observer
s efficacement. La manière la plus standard est de créer une structure de données pour enregistrer un Observer
et un tableau de chaînes avec tous les événements observés par l’instance. Voici à quoi cela ressemble :
OK, cette solution fonctionne, mais ce n’est pas un moyen efficace d’enregistrer le observer
s. Lors de la réception d’un événement à diffuser, nous devons parcourir l’ensemble observers
array et vérifiez pour chaque élément si l’événement est enregistré dans la structure de données. Dans tous les cas, nous aurions besoin de parcourir tout le tableau (O(n))
. Cela prendrait beaucoup de temps si nous avions des centaines d’articles.
La meilleure façon de résoudre ce problème de complexité est de fournir un moyen d’accéder uniquement aux observer
s inscrit à cet événement donné. Existe-t-il des structures de données dont l’opération d’accès prend O(1)
temps? Certainement un HashMap
, ou mieux encore, un dictionnaire ! Maintenant, remodelons notre observer
s et enregistrez une liste d’entre eux, afin que nous connaissions tous les objets abonnés à un événement lorsqu’il est déclenché. Voici le code :
Maintenant, nous pouvons aller droit au but et parcourir uniquement les observateurs qui s’abonnent à l’événement donné.
Maintenant que nous avons une structure de données pour enregistrer les événements et les observateurs enregistrés, implémentons nos trois opérations principales dans notre NotificationCenter
:
Comme vous pouvez le voir, lorsque nous enregistrons un nouveau observer
à un événement donné, nous devons vérifier s’il n’est pas déjà inscrit pour éviter les doublons. Après cela, nous devrions vérifier si le tableau est nil car nous avons affaire à un dictionnaire. Cela enregistrera cela dans une clé, et si c’est le cas, nous instancions le nouveau tableau avec le seul Observer
élément. Sinon, nous l’ajoutons au tableau existant.
Lorsque nous voulons désinscrire un observer
nous ne devrions supprimer que les éléments du tableau pour la clé d’événement qui fait référence à la même adresse mémoire que le observer
chose. C’est pourquoi nous avons déclaré les types de béton pour les Observer
protocole comme types de référence.
Si nous voulons informer tous observer
s’agit d’un événement, nous devons parcourir tous observer
s dans le tableau pour la clé d’événement. Après cela, nous devrions envoyer les données jointes pour appeler le receive
méthode et notifiez-le. Cette méthode est de type Any
, donc on peut diffuser n’importe quoi. Les Observers
ont pour tâche de convertir l’instance de données avec l’événement et de vérifier si c’est celui attendu.
Maintenant que nous avons mis en place notre NotificationCenter
mécanisme suite à la Observer
design pattern, créons trois classes différentes : une pour envoyer un événement au NotificationCenter
et deux autres pour mettre en œuvre le Observer
protocole et gérer les événements. Voici le code :
Comme vous pouvez le voir, nous avons déclaré une classe Sender
qui envoie manuellement des événements avec des données personnalisées au NotificationCenter
. Nous avons créé deux autres classes, Observer1
et Observer2
et ils se sont enregistrés comme observer
s à la NotificationCenter
. Ces classes sont enregistrées par heure de création et implémentent un receive
méthode de la Observer
protocole, s’attendant à recevoir un Event
avec un entier comme donnée. Les Sender
l’instance doit déclencher l’événement, et le observer
s devrait y répondre. Testons ce que nous avons :
OK, voici ce que nous avons :
Comme prévu, c’est génial. Nous recevons des sorties de chaque Observer
après avoir envoyé un événement avec le format de données attendu.
Dans cet article, nous avons parlé de la Observer
modèle de conception qui existe dans la plupart des langages de programmation orientés objet. Aussi, nous avons mis en place un NotificationCenter
qui fonctionne de la même manière que celui natif d’Apple.
Nous avons présenté les avantages et les inconvénients de la diffusion de messages avec un NotificationCenter
sur l’ancien Delegate
et Closure
mécanismes et discuté d’un moyen efficace de sauvegarder les événements liés à observer
est dans notre NotificationCenter
classer.
Enfin, nous avons appris comment s’inscrire, se désinscrire et les notifier sans avoir besoin de rechercher tous les articles pour trouver ceux qui sont enregistrés.
Cette connaissance est requise pour de nombreux défis de tableau blanc dans les entreprises américaines. J’espère que vous êtes prêt pour cela et, bien sûr, que vous avez apprécié le contenu ;).