97 votes

Propriétés en lecture seule dans Objective-C?

J'ai déclaré une propriété en lecture seule dans mon interface en tant que tel:

 @property (readonly, nonatomic, copy) NSString* eventDomain;

Peut-être que je ne suis malentendu propriétés, mais j'ai pensé que, lorsque vous déclarez comme readonly, vous pouvez utiliser le générés setter à l'intérieur de la mise en œuvre (.m) de fichiers, mais des entités externes ne peuvent pas modifier la valeur. Ce DONC, la question dit que c'est ce qui doit arriver. C'est le comportement que je suis après. Toutefois, lorsque vous essayez d'utiliser le normalisateur ou la syntaxe à point pour définir eventDomain à l'intérieur de ma méthode init, il me donne l' unrecognized selector sent to instance. d'erreur. Bien sûr, je suis @synthesizeing du bien. Essayez de l'utiliser comme ceci:

 // inside one of my init methods
 [self setEventDomain:@"someString"]; // unrecognized selector sent to instance error

Alors, suis-je le malentendu readonly déclaration sur une propriété? Ou est passe quelque chose d'autre?

120voto

Eiko Points 19502

Vous devez indiquer au compilateur que vous souhaitez également un séparateur. Une méthode courante consiste à l'insérer dans une extension privée du fichier .m:

 @interface YourClass ()

@property (nonatomic, copy) NSString* eventDomain;

@end
 

38voto

Basil Bourque Points 8938

Eiko et d'autres ont donné des réponses correctes.

Voici un moyen plus simple: accédez Directement la variable membre privée.

Exemple

Dans l'en-tête .h fichier:

@property (strong, nonatomic, readonly) NSString* foo;

Dans la mise en œuvre .m fichier:

// inside one of my init methods
self->_foo = @"someString"; // Notice the underscore prefix of var name.

C'est ça, c'est tout ce dont vous avez besoin. Pas muss, pas de chichi.

Détails

Comme de Xcode 4.4 et Compilateur LLVM 4.0 (Nouvelles Fonctionnalités dans Xcode 4.4), vous avez besoin de ne pas jouer avec les tâches abordées dans les autres réponses:

  • L' synthesize mot-clé
  • La déclaration d'une variable
  • Re-déclarer la propriété dans la mise en œuvre .m de fichier.

Après la déclaration d'une propriété foo, vous pouvez supposer Xcode a ajouté une variable membre privée nommé avec un préfixe de trait de soulignement: _foo.

Si le bien a été déclaré readwrite, Xcode, génère une méthode de lecture nommée foo et un setter nommé setFoo. Ces méthodes sont implicitement appelée lorsque vous utilisez la notation par points (mon Objet.myMethod). Si le bien a été déclaré readonly, pas de setter est généré. Cela signifie que la sauvegarde de variable, nommée avec le trait de soulignement, est pas lui-même en lecture seule. L' readonly signifie simplement qu'aucune méthode de définition a été synthétisé, et, par conséquent, à l'aide de la notation par points pour définir une valeur échoue avec une erreur du compilateur. La notation par points échoue parce que le compilateur ne vous empêche de l'appel d'une méthode (le passeur) qui n'existe pas.

La façon la plus simple de contourner cela est d'accéder directement à une variable membre, nommé par le trait de soulignement. Vous pouvez le faire même sans déclarer qu'trait de soulignement (variable nommée! Xcode est l'insertion de cette déclaration dans le cadre de la construction/processus de compilation, de sorte que votre code compilé aurez en effet la déclaration de la variable. Mais vous ne verrez jamais cette déclaration dans le fichier de code source. Pas de magie, juste de sucre syntaxique.

À l'aide de self-> est un moyen d'accéder à une variable de membre de l'objet ou de l'instance. Vous pouvez être en mesure d'omettre que, et il suffit d'utiliser la var nom. Mais je préfère utiliser les auto+flèche parce qu'il rend mon code auto-documentation. Quand vous voyez l' self->_foo vous le savez sans ambiguïté que _foo est une variable de membre sur cette instance.


Par la manière, la discussion des avantages et des inconvénients d'accesseurs de propriété rapport directe ivar accès est exactement le genre de personnes réfléchies traitement que vous allez lire dans le Dr Matt Neuberg's de la Programmation iOS livre. Je l'ai trouvé très utile pour lire et re-lire.

36voto

yano Points 863

Un autre moyen que j'ai trouvé à travailler avec des propriétés readonly est d'utiliser @synthétiser pour spécifier le magasin de sauvegarde. Par exemple

@interface MyClass

@property (readonly) int whatever;

@end

Ensuite, dans la mise en œuvre

@implementation MyClass

@synthesize whatever = _whatever;

@end

Votre méthode peut ensuite définir _whatever, car il est une variable de membre.


Une autre chose intéressante que j'ai réalisé au cours des derniers jours, vous pouvez faire readonly propriétés qui sont en écriture par les sous-classes comme tel:

(dans le fichier d'en-tête)

@interface MyClass
{
    @protected
    int _propertyBackingStore;
}

@property (readonly) int myProperty;

@end

Ensuite, dans la mise en œuvre

@synthesize myProperty = _propertyBackingStore;

Il va utiliser la déclaration dans le fichier d'en-tête, de sorte que les sous-classes peuvent mettre à jour la valeur de la propriété, tout en conservant sa readonlyness.

Légèrement malheureusement, en termes de données de masquage et de l'encapsulation.

20voto

Jonah Points 11568

Voir Personnalisation des Classes Existantes dans l'iOS Docs.

readonly Indique que la propriété est en lecture seule. Si vous spécifiez readonly, seulement une méthode de lecture est nécessaire dans le @mise en œuvre. Si vous utilisez @synthétiser dans la mise en œuvre de bloc, seule la méthode de lecture est synthétisé. En outre, si vous essayez d'attribuer une valeur à l'aide de la syntaxe à point, vous obtenez une erreur du compilateur.

Lecture seule uniquement les propriétés ont une méthode de lecture. Vous pouvez toujours définir la sauvegarde de ivar directement dans le périmètre de la classe ou de l'utilisation de la valeur de clé de codage.

9voto

BoltClock Points 249668

Vous êtes l'incompréhension de la question. Dans cette question il y a une extension de classe, a déclaré ainsi:

@interface MYShapeEditorDocument ()
@property (readwrite, copy) NSArray *shapesInOrderBackToFront;
@end

C'est ce qui génère le setter seulement visible au sein de l'implémentation de la classe. Afin Eiko dit, vous avez besoin de déclarer une classe d'extension et de remplacer la déclaration de la propriété pour indiquer au compilateur de générer un setter seulement au sein de la classe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X