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?
À 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).
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, open
accès s'applique uniquement aux classes et aux membres de la classe et il diffère de public
accè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
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
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
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
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.
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).
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!"
}
}
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.
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.
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.
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.
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.
Swift 3.0 fournit cinq contrôles d'accès différents:
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)
Dans la version bêta 6, la documentation indique qu'il existe trois modificateurs d'accès différents:
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.
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.
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.
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
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
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):
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.
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
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.
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
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
}
}
DÉMARRAGE Swift 2.2;)
Par défaut interne