J'essaie de comprendre quelque chose avec le nouveau langage Apple Swift. Disons que j'avais l'habitude de faire quelque chose comme ce qui suit en Objective-C. j'aireadonly
propriétés et elles ne peuvent pas être modifiées individuellement. Cependant, en utilisant une méthode spécifique, les propriétés sont modifiées de manière logique.
Je prends l'exemple suivant, une horloge très simple. J'écrirais ceci en Objective-C.
@interface Clock : NSObject
@property (readonly) NSUInteger hours;
@property (readonly) NSUInteger minutes;
@property (readonly) NSUInteger seconds;
- (void)incrementSeconds;
@end
@implementation Clock
- (void)incrementSeconds {
_seconds++;
if (_seconds == 60) {
_seconds = 0;
_minutes++;
if (_minutes == 60) {
_minutes = 0;
_hours++;
}
}
}
@end
Dans un but précis, nous ne pouvons pas toucher directement les secondes, les minutes et les heures, et il est seulement autorisé à incrémenter seconde par seconde à l'aide d'une méthode. Seule cette méthode pouvait changer les valeurs en utilisant l'astuce des variables d'instance.
Puisqu'il n'y a pas de telles choses dans Swift, j'essaie de trouver un équivalent. Si je fais ceci:
class Clock : NSObject {
var hours: UInt = 0
var minutes: UInt = 0
var seconds: UInt = 0
func incrementSeconds() {
self.seconds++
if self.seconds == 60 {
self.seconds = 0
self.minutes++
if self.minutes == 60 {
self.minutes = 0
self.hours++
}
}
}
}
Cela fonctionnerait, mais n'importe qui pourrait changer directement les propriétés.
Peut-être que j'avais déjà une mauvaise conception en Objective-C et c'est pourquoi le nouvel équivalent potentiel de Swift n'a pas de sens. Sinon et si quelqu'un a une réponse, je serais très reconnaissant;)
Peut-être que les futurs mécanismes de contrôle d'accès promis par Apple sont la réponse?
Merci!
la source
Réponses:
Préfixez simplement la déclaration de propriété avec
private(set)
, comme ceci:private
le garde local dans un fichier source, tout en leinternal
gardant local dans le module / projet.private(set)
crée uneread-only
propriété, tandis queprivate
définit à la foisset
etget
sur private.la source
Il existe deux façons de faire ce que vous voulez. La première consiste à avoir une propriété privée et et une propriété publique calculée qui retourne cette propriété:
Mais cela peut être réalisé d'une manière différente et plus courte, comme indiqué dans la section "Contrôle d'accès" du livre "The Swift Programming Language" :
En remarque, vous DEVEZ fournir un initialiseur public lors de la déclaration d'un type public. Même si vous fournissez des valeurs par défaut à toutes les propriétés,
init()
doit être défini explicitement public:Ceci est également expliqué dans la même section du livre, quand on parle des initialiseurs par défaut.
la source
Puisqu'il n'y a pas de contrôle d'accès (ce qui signifie que vous ne pouvez pas faire un contrat d'accès qui diffère selon l'appelant), voici ce que je ferais pour l'instant:
Cela ajoute simplement un niveau d'indirection, pour ainsi dire, à l'accès direct au compteur; une autre classe peut créer une horloge et accéder directement à son compteur. Mais l' idée - c'est-à-dire le contrat que nous essayons de faire - est qu'une autre classe ne devrait utiliser que les propriétés et méthodes de premier niveau de Clock. Nous ne pouvons pas appliquer ce contrat, mais en fait, il était pratiquement impossible de le faire également en Objective-C.
la source
En fait, le contrôle d'accès (qui n'existe pas encore dans Swift) n'est pas aussi appliqué que vous pouvez le penser dans l'Objectif C. Les gens peuvent modifier vos variables en lecture seule directement, s'ils le souhaitent vraiment. Ils ne le font tout simplement pas avec l'interface publique de la classe.
Vous pouvez faire quelque chose de similaire dans Swift (couper-coller de votre code, plus quelques modifications, je ne l'ai pas testé):
qui est identique à ce que vous avez dans Objective C sauf que les propriétés stockées réelles sont visibles dans l'interface publique.
En swift, vous pouvez aussi faire quelque chose de plus intéressant, ce que vous pouvez également faire en Objective C, mais c'est probablement plus joli en swift (édité dans le navigateur, je ne l'ai pas testé):
la source