web-dev-qa-db-fra.com

Est-ce que Swift a des modificateurs d'accès?

Dans l'instance Objective-C, les données peuvent être public, protected ou private. Par exemple:

@interface Foo : NSObject
{
  @public
    int x;
  @protected:
    int y;
  @private:
    int z;
  }
-(int) Apple;
-(int) pear;
-(int) banana;
@end

Je n'ai trouvé aucune mention de modificateurs d'accès dans la référence Swift. Est-il possible de limiter la visibilité des données dans Swift?

268
Gergo Erdosi

À partir de Swift 3.0.1 , il y a 4 niveaux d'accès , décrits ci-dessous du plus haut niveau (le moins restrictif) au plus bas (le plus restrictif).


1. open et public

Activer l'utilisation d'une entité en dehors du module de définition (cible). Vous utilisez généralement open ou public access lors de la spécification de l'interface publique à un framework.

Toutefois, openaccès s'applique uniquement aux classes et aux membres de la classe et il diffère de publicaccès comme suit:

  • public les classes et les membres de classe ne peuvent être sous-classés et remplacés que dans le module de définition (cible).
  • open les classes et les membres de classe peuvent être sous-classés et remplacés à l'intérieur et à l'extérieur du module de définition (cible).
// First.framework – A.Swift

open class A {}
// First.framework – B.Swift

public class B: A {} // ok
// Second.framework – C.Swift

import First

internal class C: A {} // ok
// Second.framework – D.Swift

import First

internal class D: B {} // error: B cannot be subclassed

2. internal

Permet à une entité d'être utilisée dans le module de définition (cible). Vous utilisez généralement internal access pour définir la structure interne d’une application ou d’un framework.

// First.framework – A.Swift

internal struct A {}
// First.framework – B.Swift

A() // ok
// Second.framework – C.Swift

import First

A() // error: A is unavailable

3. fileprivate

Limite l'utilisation d'une entité à son fichier source de définition. Vous utilisez généralement fileprivate access pour masquer les détails d'implémentation d'une fonctionnalité spécifique lorsque ces détails sont utilisés dans un fichier entier.

// First.framework – A.Swift

internal struct A {

    fileprivate static let x: Int

}

A.x // ok
// First.framework – B.Swift

A.x // error: x is not available

4. private

Limite l'utilisation d'une entité à sa déclaration englobante. Vous utilisez généralement private access pour masquer les détails d'implémentation d'une fonctionnalité spécifique lorsque ces détails ne sont utilisés que dans une seule déclaration.

// First.framework – A.Swift

internal struct A {

    private static let x: Int

    internal static func doSomethingWithX() {
        x // ok
    }

}

A.x // error: x is unavailable
406
akashivskyy

Swift 4/Swift 5

Comme indiqué dans le Swift Documentation - Access Control , Swift has 5 contrôles d'accès :

  • ouvert et public : peuvent être accessibles à partir des entités de leur module et de toutes les entités de module qui importent le module de définition.

  • internal : est accessible uniquement à partir des entités de son module. C'est le niveau d'accès par défaut.

  • fileprivate et privé : n'est accessible que de manière limitée dans un champ d'application limité dans lequel vous les définissez.



Quelle est la différence entre ouvert et publique?

open est identique à public dans les versions précédentes de Swift. Ils permettent aux classes des autres modules de les utiliser et de les hériter, c'est-à-dire: elles peuvent être sous-classées d'autres modules. En outre, ils permettent aux membres d'autres modules de les utiliser et de les remplacer. La même logique est valable pour leurs modules.

public permet aux classes d'un autre module de les utiliser, mais pas de les hériter, c'est-à-dire: elles ne peut être sous-classé à partir d'autres modules. En outre, ils permettent aux membres d'autres modules de les utiliser, mais PAS de les remplacer. Pour leurs modules, ils ont la même logique d'ouverture (ils permettent aux classes de les utiliser et en héritent; ils permettent aux membres de les utiliser et de les remplacer).


Quelle est la différence entre fileprivate et privé?

fileprivate est accessible à partir de leurs fichiers entiers.

private est accessible uniquement à partir de leur déclaration unique et vers les extensions de cette déclaration qui sont dans la même fichier; Par exemple:

// Declaring "A" class that has the two types of "private" and "fileprivate":
class A {
    private var aPrivate: String?
    fileprivate var aFileprivate: String?

    func accessMySelf() {
        // this works fine
        self.aPrivate = ""
        self.aFileprivate = ""
    }
}

// Declaring "B" for checking the abiltiy of accessing "A" class:
class B {
    func accessA() {
        // create an instance of "A" class
        let aObject = A()

        // Error! this is NOT accessable...
        aObject.aPrivate = "I CANNOT set a value for it!"

        // this works fine
        aObject.aFileprivate = "I CAN set a value for it!"
    }
}



Quelles sont les différences entre Swift 3 et Swift 4 Contrôle d'accès?

Comme indiqué dans la proposition SE-0169 , le seul raffinement ajouté à Swift 4 est que la portée du contrôle d'accès privé a été développé pour être accessible depuis les extensions de cette déclaration dans le même fichier; Par exemple:

struct MyStruct {
    private let myMessage = "Hello World"
}

extension MyStruct {
    func printMyMessage() {
        print(myMessage)
        // In Swift 3, you will get a compile time error:
        // error: 'myMessage' is inaccessible due to 'private' protection level

        // In Swift 4 it should works fine!
    }
}

Donc, il n'est pas nécessaire de déclarer myMessage en tant que fileprivate pour être accessible dans tout le fichier.

20
Ahmad F

Quand on parle de faire une "méthode privée" dans Swift ou ObjC (ou Ruby ou Java ou ...) ces méthodes ne sont pas vraiment privé. Il n'y a pas de contrôle d'accès réel autour d'eux. Toute langue qui offre même une petite introspection permet aux développeurs d’obtenir ces valeurs de l’extérieur de la classe s’ils le souhaitent vraiment.

Donc, ce dont nous parlons vraiment ici est un moyen de définir une interface publique qui ne fait que présente la fonctionnalité que nous voulons, et "cache" le reste que nous considérons comme "privé".

Le mécanisme Swift de déclaration des interfaces est le protocol, et il peut être utilisé à cette fin.

protocol MyClass {
  var publicProperty:Int {get set}
  func publicMethod(foo:String)->String
}

class MyClassImplementation : MyClass {
  var publicProperty:Int = 5
  var privateProperty:Int = 8

  func publicMethod(foo:String)->String{
    return privateMethod(foo)
  }

  func privateMethod(foo:String)->String{
    return "Hello \(foo)"
  }
}

N'oubliez pas que les protocoles sont des types de premier ordre et peuvent être utilisés n'importe où. Et, lorsqu'ils sont utilisés de cette manière, ils exposent uniquement leurs propres interfaces, pas celles du type implémenté.

Ainsi, tant que vous utiliserez MyClass au lieu de MyClassImplementation dans vos types de paramètres, etc., tout devrait fonctionner:

func breakingAndEntering(foo:MyClass)->String{
  return foo.privateMethod()
  //ERROR: 'MyClass' does not have a member named 'privateMethod'
}

Il existe des cas d'assignation directe dans lesquels vous devez être explicite avec type au lieu de vous fier à Swift pour l'inférer, mais cela ne semble guère être un facteur de désaccord:

var myClass:MyClass = MyClassImplementation()

Utiliser des protocoles de cette façon est sémantique, raisonnablement concis et ressemble beaucoup, à mes yeux, aux extensions de classe que nous utilisons à cette fin dans ObjC.

17
jemmons

Autant que je sache, il n'y a pas de mots clés "public", "privé" ou "protégé". Cela suggérerait que tout est public.

Cependant, Apple s'attend peut-être à ce que les utilisateurs utilisent “ protocoles ” (appelées interfaces par le reste du monde) et le modèle de conception d'usine pour masquer les détails de le type d'implémentation.

C'est souvent un bon modèle à utiliser de toute façon. comme il vous permet de changer votre hiérarchie de classe d'implémentation , tout en conservant la logique système de type le même.

15
Ian Ringrose

En utilisant une combinaison de protocoles, de fermetures et de classes imbriquées/internes, il est possible d'utiliser quelque chose le long du modèle de module pour masquer des informations dans Swift maintenant. Ce n'est pas super propre ou agréable à lire mais ça marche.

Exemple:

protocol HuhThing {
  var huh: Int { get set }
}

func HuhMaker() -> HuhThing {
   class InnerHuh: HuhThing {
    var innerVal: Int = 0
    var huh: Int {
      get {
        return mysteriousMath(innerVal)
      }

      set {
       innerVal = newValue / 2
      }
    }

    func mysteriousMath(number: Int) -> Int {
      return number * 3 + 2
    }
  }

  return InnerHuh()
}

HuhMaker()
var h = HuhMaker()

h.huh      // 2
h.huh = 32 
h.huh      // 50
h.huh = 39
h.huh      // 59

innerVal et mysteriousMath sont cachés ici de toute utilisation extérieure et toute tentative de creuser votre chemin dans l'objet devrait entraîner une erreur.

Je ne suis qu’une partie du chemin parcouru lors de la lecture de la docs Swift. Par conséquent, s’il ya une faille ici, veuillez la signaler, nous aimerions le savoir.

12
Dave Kapp

A partir de Xcode 6 beta 4, Swift dispose de modificateurs d'accès. À partir des notes de publication:

Le contrôle d'accès rapide a trois niveaux d'accès:

  • Les entités privées ne sont accessibles que depuis le fichier source où elles sont définies.
  • Les entités internes sont accessibles n'importe où dans la cible où elles sont définies.
  • Les entités publiques sont accessibles de n’importe où dans la cible et depuis n’importe quel autre contexte qui importe le module de la cible actuelle.

La valeur implicite par défaut est internal. Vous pouvez donc, dans une cible d'application, laisser les modificateurs d'accès désactivés, sauf si vous souhaitez être plus restrictif. Dans une cible de cadre (par exemple, si vous intégrez un cadre pour partager du code entre une application et une extension de partage ou de la vue Aujourd'hui), utilisez public pour désigner l'API que vous souhaitez exposer aux clients de votre cadre.

9
rickster

Swift 3.0 fournit cinq contrôles d'accès différents:

  1. ouvert
  2. publique
  3. interne
  4. fileprivate
  5. privé

Les accès ouverts et publics permettent d'utiliser des entités dans n'importe quel fichier source. à partir de leur module de définition, ainsi que dans un fichier source d’un autre module qui importe le module de définition. Vous utilisez généralement un accès ouvert ou public lors de la spécification de l'interface publique vers un framework.

Accès interne permet aux entités d'être utilisées dans tout fichier source à partir de leur module de définition, mais pas dans aucun fichier source en dehors de ce module. Vous utilisez généralement l’accès interne lors de la définition de la structure interne d’une application ou d’un framework.

Accès fichier-privé restreint l'utilisation d'une entité à son propre fichier source de définition. Utilisez l'accès privé au fichier pour masquer les détails d'implémentation d'une fonctionnalité spécifique lorsque ces détails sont utilisés dans un fichier entier.

Accès privé restreint l'utilisation d'une entité à la déclaration suivante. Utilisez l'accès privé pour masquer les détails d'implémentation d'une fonctionnalité spécifique lorsque ces détails ne sont utilisés que dans une seule déclaration.

Ouvrir est le niveau d'accès le plus élevé (le moins restrictif) et L’accès privé est le niveau d’accès le plus bas (le plus restrictif).

Niveaux d'accès par défaut

Toutes les entités de votre code (à quelques exceptions spécifiques) ont un niveau d'accès interne par défaut si vous ne spécifiez pas vous-même un niveau d'accès explicite. Par conséquent, dans de nombreux cas, il n'est pas nécessaire de spécifier un niveau d'accès explicite dans votre code.

La note de publication sur le sujet:

Les classes déclarées comme publiques ne peuvent plus être sous-classées en dehors de leur module de définition, et les méthodes déclarées comme publiques ne peuvent plus être remplacées en dehors de leur module de définition. Pour permettre à une classe d'être sous-classée en externe ou à une méthode d'être remplacée en externe, déclarez-la comme étant ouverte, ce qui correspond à un nouveau niveau d'accès au-delà de public. Les classes et méthodes Objective-C importées sont désormais toutes importées en tant qu'open ouvert plutôt que public. Les tests unitaires qui importent un module à l'aide d'une importation @testable seront toujours autorisés à sous-classer des classes publiques ou internes, ainsi que de remplacer des méthodes publiques ou internes. (SE-0117)

Plus d'informations & détails: Le Swift Langage de Programmation (Contrôle d'Accès)

6
CryingHippo

Dans la version bêta 6, la documentation indique qu'il existe trois modificateurs d'accès différents:

  • Publique
  • Interne
  • Privé

Et ces trois s'appliquent aux classes, protocoles, fonctions et propriétés.

public var somePublicVariable = 0
internal let someInternalConstant = 0
private func somePrivateFunction() {}

Pour plus, consultez Contrôle d'accès.

4
OliverAssad

Mécanismes de contrôle d'accès en tant que introduit dans Xcode 6 :

Swift fournit trois niveaux d'accès différents pour les entités de votre code. Ces niveaux d'accès sont relatifs au fichier source dans lequel une entité est définie et également au module auquel appartient le fichier source.

  • Accès public permet aux entités d'être utilisées dans tout fichier source à partir de leur module de définition, ainsi que dans un fichier source à partir d'un autre module qui importe le module de définition. Vous utilisez généralement un accès public lors de la spécification de l'interface publique vers un framework.
  • Accès interne permet aux entités d'être utilisées dans tout fichier source à partir de leur module de définition, mais pas dans tout fichier source en dehors de ce module. Vous utilisez généralement l’accès interne lors de la définition de la structure interne d’une application ou d’un framework.
  • Accès privé restreint l'utilisation d'une entité à son propre fichier source de définition. Utilisez un accès privé pour masquer les détails d'implémentation d'une fonctionnalité spécifique.

L'accès public est le niveau d'accès le plus élevé (le moins restrictif) et l'accès privé est le niveau d'accès le plus bas (ou le plus restrictif).

Par défaut, accecss le interne, et n'a donc pas besoin d'être spécifié. Notez également que le spécificateur private ne () ne fonctionne pas au niveau classe, mais au niveau du fichier source. Cela signifie que pour rendre certaines parties d'une classe vraiment privées, vous devez les séparer en un fichier distinct. Cela introduit également quelques cas intéressants en ce qui concerne les tests unitaires ...

Un autre point à mon propos, qui est commenté dans le lien ci-dessus, est que vous ne pouvez pas "mettre à niveau" le niveau d'accès. Si vous sous-classez quelque chose, vous pouvez le restreindre davantage, mais pas l'inverse.

Ce dernier bit affecte également les fonctions, les tuples et sûrement d’autres choses de la même manière que si une fonction utilise une classe private, il n’est pas valide d’avoir la fonction internal ou - public, car ils pourraient ne pas avoir accès à la classe private. Cela entraîne un avertissement du compilateur et vous devez redéclarer la fonction en tant que fonction private.

3
holroy

Désormais en version 4, ils ont ajouté des modificateurs d'accès à Swift.

à partir de Xcode 6 beta 4 realese notes :

Le contrôle d'accès rapide a trois niveaux d'accès:

  • private les entités ne sont accessibles que depuis le fichier source où elles sont définies.
  • Les entités internal sont accessibles n'importe où dans la cible où elles sont définies.
  • Les entités public sont accessibles de n’importe où dans la cible et depuis n’importe quel autre contexte qui importe le module de la cible actuelle.

Par défaut, la plupart des entités d'un fichier source ont un accès interne. Cela permet aux développeurs d'applications d'ignorer en grande partie le contrôle d'accès, tout en leur permettant de contrôler pleinement l'API d'un framework.

2
Alexey Globchastyy

Une des options que vous pouvez utiliser consiste à intégrer la création d'instance dans une fonction et à fournir les getters et setters appropriés dans un constructeur:

class Counter {
    let inc: () -> Int
    let dec: () -> Int

    init(start: Int) {
        var n = start

        inc = { ++n }
        dec = { --n }
    }
}


let c = Counter(start: 10)

c.inc()  // 11
c.inc()  // 12
c.dec()  // 11
2

Pour Swift 1-3:

Non, ce n'est pas possible Il n'y a pas de méthodes et de variables privées/protégées.

Tout est public.

Mise à jour Depuis Swift 4, il est possible de voir d'autres réponses dans ce fil de discussion

2
Sam

Swift 3 et 4 ont apporté beaucoup de changements également pour les niveaux d'accès des variables et des méthodes. Swift 3 et 4 ont maintenant 4 niveaux d'accès différents, où ouvert/public accès est le niveau d'accès le plus élevé (le moins restrictif) et accès privé est le niveau d'accès le plus bas (le plus restrictif):

  • Les fonctions et les membres privés ne sont accessibles qu'à partir du domaine de l'entité elle-même (struct, classe,…) et de ses extensions (dans Swift 3 également les extensions ont été restreintes)
  • fileprivate les fonctions et les membres ne sont accessibles que depuis le fichier source où ils sont déclarés.
  • interne les fonctions et les membres (par défaut, si vous n'ajoutez pas explicitement une clé de niveau d'accès Word) sont accessibles n'importe où dans la cible où ils se trouvent. défini. C'est pourquoi TestTarget n'a pas automatiquement accès à toutes les sources, elles doivent être marquées comme accessibles dans l'inspecteur de fichiers de xCode.
  • Les fonctions et les membres ouverts ou publics sont accessibles à partir de n’importe où dans la cible et de tout autre contexte qui importe le module de la cible actuelle.

Intéressant:

Au lieu de marquer chaque méthode ou membre comme "privé", vous pouvez couvrir certaines méthodes (par exemple, des fonctions d'assistance) dans une extension d'une classe/structure et marquer l'extension entière comme "privée".

class foo { }

private extension foo {
    func somePrivateHelperFunction01() { }
    func somePrivateHelperFunction02() { }
    func somePrivateHelperFunction03() { }
}

Cela peut être une bonne idée, afin d’obtenir un meilleur code maintenable. Et vous pouvez facilement basculer (par exemple pour les tests unitaires) sur une option non privée en modifiant simplement un mot.

documentation Apple

2
LukeSideWalker

enter image description here

Du plus ouvert au plus restreint:

  • open vous pouvez accéder à open classes et membres de classe à partir de n’importe quel fichier source du module définissant ou qui importe ce module. Vous pouvez sous-classer une classe open ou écraser un membre de la classe open à la fois dans leur module de définition et dans tout module qui importe ce module.

  • public autorise le même accès que open - n'importe quel fichier source de n'importe quel module - mais comporte plus restrictif et substitue. Vous ne pouvez sous-classer qu'une classe public au sein du même module . Un membre de la classe public ne peut être remplacé que par des sous-classes dans le même module . Ceci est important si vous écrivez un cadre. Si vous voulez qu'un utilisateur de ce framework puisse sous-classer une classe ou surcharger une méthode, vous devez le rendre open.

  • internal permet d'utiliser n'importe quel fichier source du module définissant , mais pas de l'extérieur de ce module. C'est le niveau d'accès par défaut .

  • fileprivate permet l'utilisation uniquement dans le fichier source qui définit.

  • private autorise uniquement l'utilisation à partir de la déclaration englobante et nouvelle dans Swift 4, à toutes les extensions de cette déclaration dans le même fichier source.

Lire la suite ici

1
yoAlex5

Le grammaire linguistique ne comporte pas les mots-clés "public", "privé" ou "protégé". Cela suggérerait que tout est public. Bien sûr, il pourrait exister une méthode alternative pour spécifier des modificateurs d'accès sans ces mots clés, mais je ne pouvais pas le trouver dans la référence du langage.

1
Scroog1

J'espère gagner du temps pour ceux qui veulent quelque chose qui s'apparente à des méthodes protégées:

Comme pour d'autres réponses, Swift fournit désormais le modificateur 'private' - défini par fichier plutôt que par classe, comme ceux de Java ou C #, par exemple. Cela signifie que si vous voulez des méthodes protégées, vous pouvez le faire avec Swift méthodes privées si elles sont dans le même fichier

  1. Créer une classe de base pour contenir les méthodes "protégées" (en fait privées)
  2. Sous-classe cette classe pour utiliser les mêmes méthodes
  3. Dans d’autres fichiers, vous ne pouvez pas accéder aux méthodes de la classe de base, même si vous sous-classe

par exemple. Fichier 1:

class BaseClass {
    private func protectedMethod() {

    }
}

class SubClass : BaseClass {
    func publicMethod() {
        self.protectedMethod()  //this is ok as they are in same file
    }
}

Fichier 2:

func test() {
    var a = BaseClass()
    a.protectedMethod() //ERROR


    var b = SubClass()
    b.protectedMethod() //ERROR
}

class SubClass2 : BaseClass {
    func publicMethod() {
        self.protectedMethod() //ERROR
    }

}

0
james_alvarez
0
OliverAssad