Remplacement d'une propriété en lecture seule dans la sous-classe
Il existe une classe qui ressemble à ça (je suis en omettant les importations pour des raisons de concision):
De Base.h:
@interface Base : NSObject
@property (strong, readonly) NSString *something;
- (id)initWithSomething:(NSString *)something;
@end
De Base.m:
@implementation Base
- (id)initWithSomething:(NSString *)something {
self = [super init];
if (self) _something = something;
return self;
}
@end
Comme vous le voyez, le "quelque chose" de la propriété est en lecture seule. Maintenant, je veux créer une sous-classe qui l'emporte sur cette propriété pour être accessible en écriture ainsi:
Sous.h:
@interface Sub : Base
@property (strong) NSString *something;
@end
Sous.m:
@implementation Sub
@end
Et le code:
principal.c:
int main(int argc, const char * argv[]) {
@autoreleasepool {
Sub *o = [Sub new];
o.something = @"foo";
NSLog(@"%@", o.something);
}
return 0;
}
Ce code:
2013-09-07 13:58:36.970 ClilTest[3094:303] *** Terminating app due to uncaught
exception 'NSInvalidArgumentException', reason: '-[Sub setSomething:]: unrecognized
selector sent to instance 0x100109ff0'
Pourquoi est-ce? Pourquoi ne pas trouver le setSelector?
Quand je le fais dans la sous-classe à la place:
Sous.m:
@implementation Sub
@synthesize something = _something;
@end
tout cela fonctionne. Est-ce à dire que la sous-classe " la propriété n'est pas synthétisé par défaut, même si elle est définie comme @property
dans le @interface
? Ne le compiler en quelque sorte de "voir" l'générée automatiquement de lecture à partir de la Base et ne génère pas de setter? Et pourquoi, je pense que le mutateur doit être généré comme il n'existe pas encore. Je suis en utilisant Xcode 4.6.2 et le projet est un Outil Cli (type de Fondation), mais la même chose se passe dans mon projet actuel, qui est une application iPhone.
Contexte: j'ai un objet lourd (instance de Base) qui nécessite une connexion Bluetooth pour certains équipements et je suis censé créer une vue contrôleur pour certaines fonctionnalités. Pour tester facilement je ne veux pas être connecté à BT (en fait, j'aurais besoin d'un périphérique physique et tester le code sur elle), je voudrais être en mesure de le tester sur le simulateur.
Ce que j'ai trouvé, c'est que j'ai tout simplement créer une sous-classe (Sous -) que des talons de quelques méthodes /propriétés et l'utiliser à la place, et lorsque le code est prêt, je viens de supprimer le code pour la sous-classe, remplacer son exemple avec la bonne, test avec un appareil, commit et push. Il fonctionne bien, sauf pour ce qui est étrange avec @property
ci-dessus.
Quelqu'un pourrait me dire ce qui se passe avec la propriété impérieuses?
- En plus de la solution de travail, je voulais ajouter que " l'augmentation du niveau de la vie privée d'un attribut va à l'encontre des principes de la programmation orientée objet. Généralement (mais pas toujours), si vous devez faire un bien plus visible (privé -> protégé, ou, protégé -> public) dans une sous-classe, alors quelque chose est faux dans le modèle. Le contraire se produit avec des méthodes. Si le parent de la classe a Une méthode, vous ne devriez pas faire Un plus privé (public -> protégé, ou, protégé -> privé) dans une sous-classe.
Vous devez vous connecter pour publier un commentaire.
Pour une propriété en lecture seule, seule une méthode de lecture est synthétisé, mais pas de méthode d'initialisation.
Et lors de la compilation de la sous-classe, le compilateur ne sait pas comment la propriété est réalisé
dans la classe de base (cela pourrait être une coutume de lecture au lieu d'un support variable d'instance).
Donc, il ne suffit pas de créer une méthode de définition de la sous-classe.
Si vous voulez avoir accès en écriture à la même variable d'instance de la sous-classe,
vous devez le déclarer comme
@protected
dans la classe de base(de sorte qu'il est accessible dans la sous-classe), de re-déclarer la propriété
en lecture-écriture dans la sous-classe, et de fournir une méthode de définition:
De Base.h:
Sous.h:
Sous.m:
Votre solution
génère le getter et le setter de la méthode dans la sous-classe, à l'aide d'un instance séparée
variable
_something
dans la sous-classe (ce qui est différentde
_something
dans la classe de base).Cela fonctionne ainsi, vous juste devez être conscient que
self.something
se réfère àdifférentes variables d'instance dans la classe de base et dans la sous-classe. Pour faire que
plus évident, vous pourrait utiliser une autre variable d'instance de la classe:
@synthesize
déclaration de la propriété dans la Base.m?La réponse qui est donnée fonctionne parfaitement bien. C'est une alternative la réponse, qui, apparemment, Apple aime un peu plus.
Vous pouvez définir un extension privée de votre classe, un
Base+Protected.h
fichier, qui doit être inclus dansBase.m
etSub.m
.Alors, dans ce nouveau fichier, vous redéfinir la propriété
readwrite
.Cette option vous permet d'utiliser l'accesseur
self.something
rathern que le ivar_something
.Remarque: vous devez toujours garder la définition de
something
dans votreBase.h
comme est.Je suppose que la sauvegarde des variables sont les mêmes lorsque la propriété n'est pas synthétisée dans la sous-classe. Donc, au moment de l'exécution le programme tente d'appeler le setSomething dans la superclasse. Mais depuis elle ne marche pas, existe-t-il une Exception est levée.