45 votes

Objective-C: Comment accédez-vous aux propriétés parent des sous-classes?

Si cette classe est définie, comment puis-je accéder à la propriété someObject dans les sous-classes sans erreur de compilation?

 @interface MyBaseClass
  // someObject property not declared here because I want it to be scoped 
  // protected. Only this class instance and subclass instances should be
  // able to see the someObject property.
@end

// This is a private interface extension...properties declared here
// won't be visible to subclasses. However, I don't see any way to 
// declare protected properties...
@interface MyBaseClass (private)
   @property (nonatomic, readwrite, retain) NSObject *someObject;
@end
 

 @interface MySubclass : MyBaseClass 
@end

@implementation MySubclass

- (id) init {
    // Try to do something with the super classes' someObject property. 
    // Always throws compile errors.

    // Semantic Issue: Property 'someObject' not found 
    // object of type 'MySubclass *'
    self.someObject = nil; 

}
@end
 



Je ne comprends évidemment pas comment fonctionne l'héritage dans objective-c. Quelqu'un pourrait-il m'éclairer?

54voto

matt Points 60113

La solution que vous êtes après est de déclarer la MyBaseClass de la propriété privée dans une extension de classe:

@interface MyBaseClass ()
@property (nonatomic, readwrite, retain) NSObject *someObject;
@end

Puis libre à vous de faire cette déclaration à la fois dans MyBaseClass et dans MySubclass. Cela vous permet de MySubclass savoir plus sur ces propriétés, de sorte que son code peut en parler.

Si la répétition vous dérange, mettre l'extension de classe dans un .h le dossier de son propre, puis l'importer dans les deux .m fichiers.

Je vais donner un exemple tiré de ma propre code. Voici MyDownloaderPrivateProperties.h:

@interface MyDownloader ()
@property (nonatomic, strong, readwrite) NSURLConnection* connection;
@property (nonatomic, copy, readwrite) NSURLRequest* request;
@property (nonatomic, strong, readwrite) NSMutableData* mutableReceivedData;
@end

Il n'y a pas de correspondant .m fichier et que tout ce qui est dans ce fichier; il est, comme il l'était, purement déclarative. Maintenant, voici le début de MyDownloader.m:

#import "MyDownloader.h"
#import "MyDownloaderPrivateProperties.h"
@implementation MyDownloader
@synthesize connection=_connection;
@synthesize request=_request;
@synthesize mutableReceivedData=_mutableReceivedData;
// ...

Et voici le début de sa sous-classe MyImageDownloader.m:

#import "MyImageDownloader.h"
#import "MyDownloaderPrivateProperties.h"

Le problème est résolu. La vie privée est préservée, car ce sont les seules classes que l'importation MyDownloaderPrivateProperties.h de sorte qu'ils sont les seules classes que savoir à propos de ces propriétés d'autant que le compilateur est concerné (et c'est tout ce que la vie privée est en Objective-C). La sous-classe peut accéder aux propriétés privées dont les accesseurs sont synthétisés par la super-classe. Je crois que c'est ce que vous vouliez accomplir en premier lieu.

14voto

justin Points 72871

c'est comment vous y accédez. comment vous déclarer est ce qui est à vous mordre:

@interface MyBaseClass : NSObject
@property (nonatomic, readwrite, retain) NSObject *someObject;
@end

c'est la voie normale pour déclarer une nouvelle objc classe.

en ajoutant des parenthèses (au lieu de déclarer la super-classe - NSObject dans ce cas), vous avez déclaré une extension de classe, qui n'est probablement pas visible à la sous-classe (par inclusion).

vous n'aurez probablement jamais besoin de déclarer une classe racine dans objc:

@interface MyBaseClass // << superclass omitted
@property (nonatomic, readwrite, retain) NSObject *someObject;
@end

NSObject (ou une sous-classe, en supposant que vous êtes la cible d'apple) pour les systèmes doivent être de la classe de base, sauf si vous êtes très expérimenté et savoir ce qu'est une racine de la classe.

les extensions de la classe sont souvent utilisés pour simuler les interfaces privées. par simuler, le compilateur ne pas appliquer cette, car elle devait être appliquée dans d'autres langues. par exemple, tous les messages sont toujours dynamique, bien que celle-ci peut (sans le savoir) remplacer les méthodes dans vos extensions, s'il est déclaré avec le même sélecteur.

4voto

Rog Points 12427

À en juger par l' () après votre nom de classe de base, on dirait que vous êtes la déclaration d'une interface privée d'extension au sein de votre implémentation de la classe, est-ce le cas? Si la variable ne sera accessible depuis l'intérieur de la classe de mise en œuvre.

Est-ce que votre MyBaseClass hérite de NSObject directement?

Si oui, vous devez déclarer l' someObject propriété dans votre fichier d'interface, comme dans:

@interface MyBaseClass : NSObject
{
}
@property (nonatomic, retain) NSObject *someObject;

Et puis faire la synthèse, comme vous le faites déjà.

1voto

Elise van Looij Points 2254

Le vrai problème est dans la méthode init, qui devrait se lire:

- (id)init {
    self = [super init];

    if (self) {
        // initialize instance variables here without compiler errors
        self.someObject = nil;
    }

    return self;
}

Comme il est indiqué dans l'Accès des Variables d'Instance Directement à partir de l'Initialiseur de Méthodes dans la Programmation Objective-C guide:

En appelant [super init] sur la première ligne de la méthode, un objet est initialisé à partir de la racine de la classe vers le bas par le biais de chaque sous-classe init mise en œuvre dans l'ordre.

0voto

Gustav Larsson Points 3416

Vous devriez d'abord construire un objet, puis je crois que cela devrait fonctionner

 - (id)init {
    self = [super init];
    if (self) {
        self.someObject = nil;
    }
    return self;
}
 

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