Programmation rapide 101 : Maîtriser les protocoles et les délégués (2ème partie)

Dans la deuxième partie de cet article sur les protocoles Swift, vous apprendrez les utilisations pratiques de la déclaration de protocoles personnalisés dans vos propres applications, et vous découvrirez comment ils améliorent l'architecture de vos applications et les rendent plus faciles à améliorer et à étendre.

Dans la première partie de ce billet, j'ai montré comment mettre en œuvre les protocoles Cocoa Touch existants dans vos applications. Vous allez maintenant apprendre comment et pourquoi créer la vôtre. Tout d'abord, nous devons couvrir la construction de base d'un protocole Swift.

Maîtrisez votre iPhone en une minute par jour :

Inscrivez-vous à la newsletter "Tip of the Day" de iphonologie et nous vous enverrons chaque jour un conseil pour gagner du temps et tirer le meilleur parti de votre iPhone ou iPad.

Déclarer vos propres protocoles

Voici la syntaxe de base pour déclarer un protocole dans Swift :

Méthodes du protocole

Un protocole peut spécifier des méthodes d'instance et de type qui doivent être implémentées par des classes qui s'y conforment.

Vous déclarez les méthodes d'un protocole de la même manière que vous les déclarez pour une classe, mais vous n'incluez pas les accolades ni le code d'implémentation.

Voici un exemple de méthode d'instance qui accepte un seul paramètre entier et renvoie une valeur booléenne :

Pour déclarer une méthode de type, utilisez le mot-clé class . Les méthodes de type suivantes n'acceptent aucun paramètre et renvoient une valeur entière :

Propriétés du protocole

Un protocole peut également déclarer des propriétés d'instance et de type. Le protocole spécifie les noms et les types des propriétés, mais ne précise pas si elles doivent être stockées ou calculées. Cependant, un protocole doit préciser si une propriété est en lecture seule ou en lecture-écriture.

Par exemple, le protocole suivant déclare une propriété booléenne en lecture-écriture nommée verbose et une propriété entière en lecture seule nommée numberOfRetries :

Membres du protocole facultatif

Par défaut, les méthodes et les propriétés déclarées dans un protocole sont requises - ce qui signifie que toute classe adoptant le protocole doit les mettre en œuvre.

Cependant, vous pouvez indiquer qu'un membre particulier est facultatif en utilisant le mot-clé optional en conjonction avec l'attribut @objc .

Par exemple, le protocole suivant déclare la propriété verbose comme facultative et la propriété numberOfRetries comme obligatoire :

L'attribut @objc peut être utilisé avant toute classe, méthode ou propriété Swift. Il indique que vous voulez y accéder depuis l'Objective-C. Dans ce cas, même si vous n'y accédez pas depuis l'Objective-C, vous devez l'utiliser pour marquer les membres de votre protocole comme facultatif .

Vérification de la conformité au protocole

Parfois, vous voudrez peut-être vérifier si une classe est conforme à un protocole particulier. Utilisez l'opérateur Swift is pour vérifier la conformité, et utilisez son comme ? et comme opérateurs pour lancer à un protocole particulier.Les protocoles utilisent la même syntaxe que la vérification de la conformité à un type.

Il y a deux réserves importantes concernant la vérification de la conformité au protocole :

  1. Vous devez marquer votre protocole avec l'attribut @objc (comme indiqué dans la section précédente) pour en vérifier la conformité.
  1. Si vous marquez votre protocole avec l'attribut @objc , vous ne pouvez appliquer le protocole qu'aux classes et non aux structures ou aux énumérations.

Protocole Héritage

Il y a deux aspects de l'héritage des protocoles.

Premièrement, les protocoles sont hérités par des sous-classes. Si une classe adopte un protocole, ses sous-classes adoptent automatiquement le protocole.

Le deuxième aspect de l'héritage des protocoles est que vous pouvez sous-classer et étendre le protocole lui-même.

Un protocole peut hériter d'un ou de plusieurs autres protocoles et les étendre encore davantage. Par exemple, dans le code suivant, les protocoles Localizable et Securable sont hérités par le protocole LocalizeableSecureableSustainable , qui ajoute sa propre propriété isSustainable :

Une classe qui adopte LocalizeableSecurableSustainable doit implémenter tous les membres des protocoles dont elle hérite ainsi que les membres qu'elle déclare. Par exemple :

Composition du protocole

Vous pouvez spécifier qu'une variable, une propriété ou un paramètre contient des types conformes à plusieurs protocoles.

Par exemple, le code suivant déclare une variable nommée localizeSecure qui contient des types conformes aux protocoles Localizable et Secureable :

Compte tenu de cette déclaration, un type qui se conforme uniquement au protocole Localisable ou uniquement au protocole Sécurisable ne peut pas être stocké dans cette variable. Le type doit être conforme aux deux protocoles.

Notez que les compositions de protocole ne créent pas de nouveau protocole. Elles déclarent simplement une combinaison temporaire de protocoles.

Utilisation pratique des protocoles

Où pourriez-vous utiliser les protocoles dans vos projets iOS ? Par exemple, vous pourriez déclarer un protocole pour la récupération et le stockage des paramètres de l'application :

Plusieurs classes peuvent implémenter ce protocole et fournir des implémentations complètement différentes pour leurs méthodes. Par exemple, une classe peut lire et écrire des paramètres dans un fichier local :

Une autre classe peut lire et écrire des paramètres dans une base de données :

Dans Figure 1 , la forme de sucette sur le bord droit de chaque classe indique qu'elle adopte le protocole AppSetting .

Figure 1 - Classes implémentant un protocole

Un protocole déclare la signature des méthodes qu'une classe doit mettre en œuvre pour adopter le protocole, mais il ne précise pas le contenu et le comportement des méthodes. Cela offre une grande flexibilité, vous permettant d'étendre facilement votre application à l'avenir. Par exemple, vous pouvez décider de stocker les paramètres de l'application sur le web. Vous pouvez créer une troisième classe SettingsInternet , adopter le protocole AppSetting , et vous êtes prêt à partir !

Dans Swift, les protocoles sont des types à part entière. Concrètement, cela signifie que vous pouvez déclarer une variable comme étant un type de protocole spécifique, et qu'il peut stocker une référence à toute classe qui adopte le protocole.

Par exemple, le code suivant déclare une variable de type settings AppSetting (le protocole). Il stocke ensuite une instance de la classe SettingsLocalFile dans la variable, et ensuite, une instance de SettingsDatabase :

Si vous stockez une instance d'une classe qui n'adopte pas le protocole AppSetting, cela produit une erreur de compilation qui dit Le type "x" n'est pas conforme au protocole AppSetting .

Vous pouvez même spécifier un protocole comme le type d'un tableau ou d'un dictionnaire. Par exemple, vous pouvez déclarer un protocole nommé Localisable , et ensuite créer un tableau d'objets Localisable :

Vous pouvez déclarer un protocole dans son propre fichier de classe, ou dans le même fichier qu'une classe apparentée. Par exemple, la classe UIPickerView a un protocole associé UIPickerViewDelegate qui définit les méthodes qu'un délégué doit mettre en œuvre. Dans ce cas, il est logique de déclarer le protocole dans le même fichier que la classe UIPickerView .

Retour des valeurs à partir des contrôleurs de vue

Une autre utilisation pratique des protocoles consiste à renvoyer des valeurs d'un contrôleur de vue à un autre. Voyons un exemple de cela. Pour continuer, téléchargez l'exemple de projet à partir de ce lien .

  1. Ouvrez le projet iAppsReview que vous venez de télécharger.
  1. Sélectionnez le fichier Main.storyboard dans le navigateur de projet. En haut à droite du storyboard se trouvent les scènes illustrées dans Figure 2 .

Figure 2 - Deux scènes utilisent le App Category scene.

Lorsque vous touchez la ligne App Category en haut de ces scènes, elles naviguent vers la scène App Category . Lorsque vous sélectionnez une catégorie dans la liste et que vous appuyez sur le bouton Retour , la ligne en haut de la scène d'origine affiche la catégorie sélectionnée.

Alors comment la scène App Category doit-elle faire passer la catégorie sélectionnée à la scène d'origine ?

Parlons d'abord de la façon dont et non de le faire. La figure 3 montre une mauvaise solution à ce problème. Dans cet exemple, lorsqu'un contrôleur de vues navigue vers AppCategoryViewController , il enregistre une référence à lui-même dans la propriété originatingController .

Figure 3 - Une mauvaise solution !

Lorsqu'un utilisateur sélectionne une catégorie dans la liste, l'opérateur AppCategoryViewController utilise l'opérateur Swift is pour vérifier le type du contrôleur d'origine. Si c'est WriteReview , alors il exécute un ensemble d'actions pour renvoyer la catégorie sélectionnée. Si c'est OnlineReview , il exécute une autre série d'actions.

Lorsque j'effectue des revues de code pour des sociétés de logiciels, je vois beaucoup de cette approche "tester le type d'objet et effectuer un ensemble d'actions". C'est un exemple de couplage serré, ce qui n'est pas une bonne chose. Le AppCategoryViewController en sait trop sur les scènes qui l'appellent. En fait, si vous ajoutez une nouvelle scène à votre application qui doit accéder à la liste des catégories, vous devez ajouter une autre déclaration if dans le AppCategoryViewController afin d'accueillir la nouvelle scène (ou peut-être même la convertir en une déclaration switch ).

L'utilisation d'un protocole est une bien meilleure solution. La figure 4 montre comment un protocole peut être utilisé pour résoudre élégamment ce problème.

Figure 4 - Utiliser un protocole pour une meilleure solution.

Voici les points clés tels qu'ils sont numérotés dans le diagramme de classe :

  1. La classe AppCategoryViewController déclare un protocole nommé AppCategoryDelegate qui contient une seule méthode updateAppCategory que tous les contrôleurs de vue d'origine doivent implémenter.
  1. Le AppCategoryViewController possède une propriété delegate qui est le type du protocole AppCategoryDelegate . Les contrôleurs de vue d'origine stockent une référence à eux-mêmes dans cette propriété.
  1. Lorsqu'une catégorie d'application est sélectionnée dans la liste, le AppCategoryViewController appelle la méthode updateAppCategory sur le contrôleur de vue stocké dans la propriété delegate , en passant la CategoryEntity sélectionnée.
  1. La méthode du contrôleur de vue d'origine updateAppCategory est exécutée, et la catégorie d'application nouvellement sélectionnée est affichée.

La figure 5 contient un diagramme de séquence qui fournit une vue étape par étape du fonctionnement du protocole au moment de l'exécution.

Figure 5 - Le diagramme de séquence du protocole

  1. La méthode prepareForSegue du contrôleur de vue d'origine est appelée.
  1. Le contrôleur de vue d'origine stocke une référence à lui-même dans la propriété AppCategoryViewController delegate et le contrôle est transmis au AppCategoryViewController .
  1. Une catégorie d'application est sélectionnée dans la liste.
  1. Le AppCategoryViewController appelle la méthode updateCategory sur le contrôleur de vue d'origine, en passant une référence à l'AppCategoryEntity sélectionnée .

Maintenant que vous avez une vue d'ensemble du fonctionnement du protocole, examinons le code qui permet à tout cela de se produire.

  1. Sélectionnez le fichier AppCategoryViewController.swift dans le navigateur de projet.
  1. En haut du fichier de code se trouve un protocole nommé AppCategoryDelegate :

Ce protocole déclare une méthode updateAppCategory que tous les contrôleurs de vue d'origine doivent mettre en œuvre afin d'être notifiés lorsque l'utilisateur sélectionne une catégorie d'application dans la liste.

Cela signifie qu'un contrôleur de vue d'origine doit avoir une méthode appelée updateAppCategory qui accepte un paramètre de type AppCategoryEntity .

  1. Regardez un peu plus bas dans le fichier de code pour voir la propriété delegate :

Notez que son type est le protocole AppCategoryDelegate . Un contrôleur de vue d'origine qui implémente le protocole AppCategoryDelegate peut stocker une référence à lui-même dans cette propriété.

  1. Faites défiler jusqu'à tableView:didSelectRowAtIndexPath . Cette méthode est appelée lorsqu'une catégorie d'application est sélectionnée au moment de l'exécution. Voici la dernière ligne de code de cette méthode :

Ce code appelle la méthode updateAppCategory sur l'objet contrôleur de vue d'origine stocké dans la propriété delegate , en passant l'AppCategoryEntity sélectionnée.

  1. Sélectionnez le fichier WriteReviewViewController.swift dans le navigateur de projet. En haut du fichier, ce contrôleur de vues adopte le protocole AppCategoryDelegate :

  1. La méthode prepareForSegue est appelée juste avant de naviguer vers le AppCategoryViewController . Dans la dernière ligne de cette méthode, le contrôleur de vue d'origine stocke une référence à lui-même dans la propriété delegate du AppCategoryViewController :

  1. Au bas du fichier se trouve l'implémentation de la méthode du protocole updateAppCategory :

Ce code met à jour la ligne pour afficher l'AppCategoryEntity renvoyée par le AppCategoryViewController .

Tester le protocole en cours d'exécution

Maintenant, passons ce code en revue au moment de l'exécution afin d'obtenir une image encore plus claire de toutes les pièces mobiles.

  1. Dans la classe WriteReviewViewController , ajoutez un point d'arrêt sur la dernière ligne de code de la méthode prepareForSegue ( Figure 6 ).

Figure 6 - Fixer un point d'arrêt dans prepareForSegue .

  1. Ensuite, définissez un point d'arrêt sur la première ligne de code dans la méthode updateAppCategory ( Figure 7 ).

Figure 7 - Définir un point d'arrêt dans updateAppCategory .

  1. Sélectionnez le fichier AppCategoryViewController.swift dans le navigateur de projet. Définissez un point d'arrêt sur la dernière ligne de la tableView:didSelectRowAtIndexPath : ( Figure 8 ).

Figure 8 - Définir un point d'arrêt dans tableView:didSelectRowAtIndexPath :.

  1. Appuyez sur le bouton "Run" de Xcode . Lorsque l'application apparaît dans le simulateur, sélectionnez l'option Écrire une critique dans le premier écran. Cela vous amène à la scène Write Review ( Figure 9 ).

Figure 9 - La scène de la Revue d'écriture

  1. En haut de la scène, cliquez sur la cellule App Category. Le premier point de rupture est alors atteint ( Figure 6 ) et le WriteReviewViewController stocke une référence à lui-même dans la propriété AppCategoryViewController delegate .
  1. dans la barre d'outils Debug, cliquez sur Continuer. Cela permet de naviguer dans l'application jusqu'à la scène de la catégorie d'application ( Figure 10 ).

Figure 10 - La scène de la catégorie App

  1. Sélectionnez une catégorie d'application dans la liste. Lorsque vous faites cela, vous atteignez le point d'arrêt dans la tableView:didSelectRowAtIndexPath : méthode ( Figure 8 ). Le AppCategoryViewController appelle la méthode updateAppCategory sur le contrôleur de vue stocké dans sa propriété delegate , en passant l'AppCategoryEntity actuellement sélectionnée .
  1. Dans la barre d'outils Debug, cliquez sur le bouton Continuer. Cela vous amène au point d'arrêt de la méthode updateAppCategory du contrôleur de vue d'origine ( Figure 7 ). Ce code obtient le nom de la catégorie d'application nouvellement sélectionnée, le stocke dans la ligne en haut de la scène, puis indique à la vue du tableau de recharger ses données, ce qui rafraîchit la ligne.
  1. Cliquez sur Continuer dans la barre d'outils de débogage. Cela affiche la scène Catégorie d'application avec une coche à côté de la catégorie d'application nouvellement sélectionnée ( Figure 11 ).

Figure 11 - Une coche à côté de l'élément sélectionné

  1. Cliquez sur le bouton Retour en haut de la scène de la catégorie App . Cela vous ramène à la scène "Write Review" où vous pouvez voir la nouvelle catégorie sélectionnée affichée dans la cellule en haut de l'écran ( Figure 12 ).

Figure 12 - L'élément nouvellement sélectionné est affiché dans la ligne en haut de l'écran !

C'est une excellente solution, parce qu'elle est vaguement couplée. Le AppCategoryViewController en sait très peu sur les contrôleurs de vues qui l'appellent. En fait, la seule chose qu'il sait est que le contrôleur de vues a une méthode nommée updateAppCategory qui accepte un paramètre AppCategoryEntity . C'est tout !

Maintenant, chaque fois que vous avez un autre contrôleur de vues qui doit utiliser la scène App Category , vous n'avez pas à faire de changements à la classe AppCategoryViewController . Ce est un couplage lâche.

Cette solution élégante vous est proposée par les protocoles de Swift !

Conclusion

Une fois que vous avez appris la syntaxe, il faut un peu d'effort pour créer un protocole. Le gain en termes de flexibilité et de temps gagné plus tard en vaut la peine !

Click to rate this post!
[Total: 0 Average: 0]

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *