web-dev-qa-db-fra.com

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

Si cette classe est définie, comment accéder à la propriété someObject dans les sous-classes sans erreurs 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 l'objectif-c. Quelqu'un pourrait-il m'éclairer?

44
memmons

La solution que vous recherchez consiste à déclarer la propriété privée MyBaseClass dans une extension de classe:

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

Vous êtes alors libre de faire cette déclaration les deux dans MyBaseClass et dans MySubclass. Cela permet à MySubclass de connaître ces propriétés afin que son code puisse en parler.

Si la répétition vous dérange, placez l'extension de classe dans un fichier .h qui lui est propre et importez-la dans les deux fichiers .m.

Je vais donner un exemple de mon 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 fichier . M correspondant et c'est tout ce qu'il y a dans ce fichier; il est, pour ainsi dire, purement déclaratif. Voici maintenant 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"

Problème résolu. La confidentialité est préservée, car ce sont les seules classes qui importent MyDownloaderPrivateProperties.h donc ce sont les seules classes qui connaissent ces propriétés en ce qui concerne le compilateur (et c'est tout ce que la confidentialité est dans 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.

54
matt

c'est ainsi que vous y accédez. comment vous les déclarez est ce qui vous mord:

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

c'est la manière normale de déclarer une nouvelle classe objc.

en ajoutant les parenthèses (au lieu de déclarer la superclasse - NSObject dans ce cas), vous avez déclaré une extension de classe, qui n'est probablement pas visible pour la sous-classe (via l'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 de, en supposant que vous êtes les systèmes Apple cibles) devrait être la classe de base, sauf si vous êtes très expérimenté et savez à quoi sert une classe racine.

les extensions de classe sont souvent utilisées pour "simuler" des interfaces privées. par simuler, le compilateur n'applique pas cela, car il serait appliqué dans d'autres langues. par exemple, tous les messages sont toujours dynamiques, bien que la sous-classe puisse (sans le savoir) remplacer les méthodes dans vos extensions, si elle est déclarée avec le même sélecteur.

14
justin

A en juger par le () après le nom de votre classe de base, il semble que vous déclariez une extension d'interface privée dans votre implémentation de classe, est-ce le cas? Si c'est le cas, la variable ne sera accessible qu'à partir de cette implémentation de classe.

Votre MyBaseClass hérite-t-il directement de NSObject?

Si c'est le cas, vous devez déclarer la propriété someObject dans votre fichier d'interface, comme dans:

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

Et puis synthétisez-le comme vous le faites déjà.

4
Rog

Il s'agit d'une alternative qui répond à la plupart des objectifs.

Dans votre en-tête, définissez l'interface

@interface MyBaseClass : NSObject {
    NSObject *inheritableObject;
}
@property (readonly) NSObject *inheritableObject;

Vous pouvez maintenant modifier l'héritableObjet dans MyBaseClass ainsi que dans n'importe quelle classe qui hérite de MyBaseClass. Cependant, de l'extérieur, c'est en lecture seule. Pas privé comme dans le cas de @interface MyBaseClass (), mais protégé des changements incontrôlés.

0
Hans Bot