Swift readonly external, propriété interne readwrite

103

Dans Swift, quelle est la manière conventionnelle de définir le modèle commun où une propriété doit être en lecture seule en externe, mais modifiable en interne par la classe (et les sous-classes) qui la possèdent.

En Objective-C, il existe les options suivantes:

  • Déclarez la propriété en lecture seule dans l'interface et utilisez une extension de classe pour accéder à la propriété en interne. Il s'agit d'un accès basé sur les messages, il fonctionne donc bien avec KVO, atomicité, etc.
  • Déclarez la propriété en lecture seule dans l'interface, mais accédez à l'ivar de support en interne. Comme l'accès par défaut pour un ivar est protégé, cela fonctionne bien dans une hiérarchie de classes, où les sous-classes pourront également modifier la valeur, mais le champ est autrement en lecture seule.

En Java, la convention est:

  • Déclarez un champ protégé et implémentez un getter (méthode) public en lecture seule.

Quelle est l'idiome de Swift?

Jasper Blues
la source

Réponses:

219

Étant donné une propriété de classe, vous pouvez spécifier un niveau d'accès différent en préfixant la déclaration de propriété avec le modificateur d'accès suivi par getou setentre parenthèses. Par exemple, une propriété de classe avec un getter public et un setter privé sera déclarée comme:

private(set) public var readonlyProperty: Int

Lectures suggérées: Getters and Setters

Les considérations de Martin sur le niveau d'accessibilité sont toujours valables - c'est-à-dire qu'il n'y a pas de protectedmodificateur, internalrestreint l'accès au module uniquement, privateau fichier courant uniquement, etpublic sans aucune restriction.

Swift 3 notes

2 nouveaux modificateurs d'accès, fileprivateet openont été ajoutés à la langue, tandis que privateet publicont été légèrement modifiés:

  • opens'applique uniquement aux membres de classe et de classe: il est utilisé pour permettre à une classe d'être sous-classée ou à un membre d'être remplacé en dehors du module où ils sont définis. publicà la place, rend la classe ou le membre accessible au public, mais ne peut pas être hérité ni remplacé

  • privaterend désormais un membre visible et accessible à partir de la déclaration englobante uniquement, alors que fileprivatepour l'ensemble du fichier où il est contenu

Plus de détails ici .

Antonio
la source
Agréable! (J'ai pris la liberté d'ajouter le varmot-clé manquant pour le faire compiler.)
Martin R
oh merci beaucoup :) J'ai l'habitude de copier du terrain de jeu et de coller, mais cette fois, je l'ai probablement mal fait.
Antonio le
10
Notez qu'en janvier 2015, cette syntaxe n'est pas tout à fait correcte si la classe externe n'est pas public- elle devrait l'être internalou rien du tout (ce qui par défaut est la classe - publicou internal) - c'estprivate(set) var readonlyProperty: Int
Grimxn
1
Eh bien, la syntaxe est correcte en tenant compte du fait que juste avant le code, j'ai écrit une propriété de classe avec un getter public et un setter privé - ce n'est qu'un exemple. Mais oui, les modificateurs d'accès pour les propriétés doivent être "compatibles" avec le modificateur d'accès class / struct.
Antonio
En ce qui concerne le dernier paragraphe, je suppose que cela a changé depuis que la réponse a été écrite, mais privatese limite maintenant à la déclaration actuelle (pas au fichier) et fileprivateest disponible pour la restriction au fichier actuel. A également publicquelques restrictions et openest nécessaire pour aucune restriction. Détails ici .
Nigel B.Peck
2

Selon @Antonio, nous pouvons utiliser une seule propriété pour accéder en tant que readOnlyvaleur de propriété publiquement et en readWriteprivé. Ci-dessous mon illustration:

class MyClass {

    private(set) public var publicReadOnly: Int = 10

    //as below, we can modify the value within same class which is private access
    func increment() {
        publicReadOnly += 1
    }

    func decrement() {
        publicReadOnly -= 1
    }
}

let object = MyClass()
print("Initial  valule: \(object.publicReadOnly)")

//For below line we get the compile error saying : "Left side of mutating operator isn't mutable: 'publicReadOnly' setter is inaccessible"
//object.publicReadOnly += 1

object.increment()
print("After increment method call: \(object.publicReadOnly)")

object.decrement()
print("After decrement method call: \(object.publicReadOnly)")

Et voici la sortie:

  Initial  valule: 10
  After increment method call: 11
  After decrement method call: 10
Santosh
la source