Le concept de contrôle d’accès nous permet de restreindre l’accès aux types, fonctions et autres déclarations par un autre code. Swift offre cinq niveaux différents de contrôle d’accès, et en tirer pleinement parti peut être crucial pour écrire des programmes qui ont des préoccupations clairement séparées et une structure robuste.

Lorsque nous définissons un nouveau type, propriété ou fonction dans Swift, il aura le niveau d’accès internal par défaut. Cela signifie qu’il sera visible par tous les autres codes qui vivent dans le même module, tels qu’une application, une extension système, un framework ou un package Swift.

Par exemple, disons que nous construisons une application de shopping et que nous avons défini une classe appelée PriceCalculator qui nous permet de calculer le prix total d’un tableau de produits:

Comme nous ne spécifions actuellement aucun niveau d’accès explicite, notre classe PriceCalculator (et sa méthode calculatePrice) sera accessible de n’importe où dans notre application. Cependant, si nous cherchons à partager notre nouvelle classe avec d’autres modules (nous pourrions, par exemple, l’implémenter dans un cadre que nous partageons entre notre application principale et une extension, ou une application Apple Watch compagnon), alors nous devrons la rendre public pour qu’elle soit visible dans ces contextes externes:

Cependant, le changement ci-dessus n’est pas tout à fait suffisant. Bien que nous puissions maintenant trouver notre classe en dehors du module dans lequel elle est définie, nous ne pouvons en créer aucune instance — car son initialiseur (implicite) est, comme tout autre code, internal par défaut. Pour résoudre ce problème, définissons un initialiseur public, que nous laisserons vide car il n’y a pas de travail réel à faire en son sein:

public class PriceCalculator { public init() {} ...}

Nous sommes maintenant en mesure de trouver, d’initialiser et d’appeler notre PriceCalculator à l’intérieur et à l’extérieur de son module — fantastique. Mais disons maintenant que nous cherchons également à le sous-classer afin de le modifier ou d’y ajouter de nouvelles fonctionnalités. Bien que cela soit actuellement possible dans son propre module, c’est encore quelque chose qui est empêché en dehors de celui-ci.

Pour changer cela, nous devrons utiliser le niveau de contrôle d’accès actuellement le plus ouvert de Swift, qui est nommé de manière appropriée open:

open class PriceCalculator { ...}

Avec la modification ci—dessus en place, nous pouvons maintenant créer des sous-classes personnalisées de PriceCalculator n’importe où – qui peuvent avoir de nouveaux initialiseurs, de nouvelles propriétés et de nouvelles méthodes. Voici comment nous pourrions l’utiliser pour implémenter un DiscountedPriceCalculator, ce qui nous permet d’appliquer un discount donné à tous les calculs de prix:

Ci-dessus, nous définissons une toute nouvelle méthode de calcul des prix, mais il serait sans doute beaucoup plus approprié de remplacer et de modifier la méthode calculatePrice existante que nous avons héritée de notre classe de base à la place. De cette façon, il n’y aurait pas de confusion autour de la méthode à appeler, et nous pourrions garder nos deux classes cohérentes.

Pour pouvoir le faire, nous devons à nouveau marquer la déclaration d’origine — cette fois notre déclaration de méthode calculatePrice – comme open:

open class PriceCalculator { public init() {} open func calculatePrice(for products: ) -> Int { ... }}

Avec ce qui précède en place, nous pouvons maintenant remplacer librement calculatePrice, plutôt que d’avoir à créer une méthode séparée:

Ce sont donc internal, public et

Allons donc maintenant de l’autre côté du spectre des niveaux d’accès et examinons le niveau le plus restrictif — private. Tout type, propriété ou méthode marqué comme private ne sera visible que dans son propre type (qui inclut également les extensions sur ce type défini dans le même fichier).

Tout ce qui devrait être considéré comme un détail d’implémentation privé d’un type donné devrait sans doute être marqué comme private. Par exemple, la propriété discount de notre calculateur de prix d’avant n’était vraiment destinée qu’à être utilisée dans sa propre classe — alors allons-y et rendons cette propriété privée:

class DiscountedPriceCalculator: PriceCalculator { private let discount: Int ...}

Notre implémentation précédente continuera à fonctionner exactement de la même manière qu’auparavant, puisque discount restera entièrement visible dans notre classe DiscountedPriceCalculator. Cependant, si nous voulions étendre légèrement cette visibilité pour inclure également d’autres types définis dans le même fichier, nous devrions utiliser fileprivate — ce qui fait exactement ce à quoi cela ressemble, il garde une déclaration privée dans le fichier dans lequel elle est définie:

class DiscountedPriceCalculator: PriceCalculator { fileprivate let discount: Int ...}

Avec le changement ci—dessus en place, nous pouvons maintenant accéder à notre propriété discount à partir du code associé défini dans le même fichier – comme cette extension sur UIAlertController qui nous permet d’afficher facilement une description de prix pour un tableau de produits dans une alerte:

En ce qui concerne les fonctions, types et extensions libres, private et fileprivate agissent exactement de la même manière. Ils ne sont différents que lorsqu’ils sont appliqués aux déclarations définies dans un type.

Donc, pour résumer, ce sont les cinq niveaux de contrôle d’accès que Swift offre actuellement:

  • private conserve une propriété ou une fonction privée dans son type englobant, y compris les extensions de ce type définies dans le même fichier. Lorsqu’il est appliqué à un type, une fonction ou une extension de niveau supérieur, il agit de la même manière que fileprivate.
  • fileprivate rend une déclaration visible dans tout le fichier dans lequel elle est définie, tout en la cachant de tout autre code.
  • internal est le niveau d’accès par défaut et rend une déclaration visible dans l’ensemble du module dans lequel elle est définie.
  • public révèle une fonction, un type, une extension ou une propriété en dehors de son module.
  • open permet de sous-classer une classe et de remplacer une fonction ou une propriété en dehors de son module.

En général, il est souvent préférable de commencer par le niveau d’accès le plus restrictif qu’une déclaration donnée puisse pratiquement avoir, puis d’ouvrir les choses plus tard si nécessaire. De cette façon, nous limitons les possibilités d’interaction entre nos différents types et fonctions, ce qui peut sembler à première vue une mauvaise chose, mais est souvent vraiment essentiel pour construire des systèmes maintenables et bien structurés.

Merci d’avoir lu! Note

(Notez que cet article n’est pas entré dans les modificateurs d’accès spécifiques à la mutation, tels que private(set). Ceux-ci seront couverts par un autre article de base à l’avenir.)

Soutenez Swift par Sundell en consultant ce sponsor:

Instaboug: Résolvez les bogues, les plantages et autres problèmes beaucoup plus rapidement en utilisant les traces de pile détaillées, les journaux réseau et les événements d’interface utilisateur qu’Instabug attache automatiquement à chaque rapport de bogue. Utilisé à la fois par moi et par des milliers d’équipes de développement iOS à travers le monde. Essayez-le gratuitement et intégrez-le avec une seule ligne de code.

Laisser un commentaire

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