Cela est possible en utilisant une extension de classe (pas de catégorie) que vous incluez dans les fichiers d'implémentation de la classe de base et des sous-classes.
Une extension de classe est définie de manière similaire à une catégorie, mais sans le nom de la catégorie :
@interface MyClass ()
Dans une extension de classe, vous pouvez déclarer des propriétés, qui pourront synthétiser les ivars de sauvegarde (la synthèse automatique des ivars fonctionne également ici avec Xcode > 4.4).
Dans la classe d'extension, vous pouvez remplacer/ajuster les propriétés (passer de readonly à readwrite, etc.), et ajouter des propriétés et des méthodes qui seront "visibles" dans les fichiers d'implémentation (mais notez que les propriétés et les méthodes ne sont pas vraiment privées et peuvent toujours être appelées par le sélecteur).
D'autres ont suggéré d'utiliser un fichier d'en-tête séparé MyClass_protected.h pour cela, mais cela peut également être fait dans le fichier d'en-tête principal en utilisant #ifdef
comme ceci :
Exemple :
BaseClass.h
@interface BaseClass : NSObject
// foo est en lecture seule pour les consommateurs de la classe
@property (nonatomic, readonly) NSString *foo;
@end
#ifdef BaseClass_protected
// ceci est l'extension de classe, où vous définissez
// les propriétés et méthodes "protégées" de la classe
@interface BaseClass ()
// foo est maintenant en lecture-écriture
@property (nonatomic, readwrite) NSString *foo;
// bar est visible dans l'implémentation des sous-classes
@property (nonatomic, readwrite) int bar;
-(void)baz;
@end
#endif
BaseClass.m
// cela importera BaseClass.h
// avec BaseClass_protected défini,
// donc cela inclura également l'extension de classe protégée
#define BaseClass_protected
#import "BaseClass.h"
@implementation BaseClass
-(void)baz {
self.foo = @"test";
self.bar = 123;
}
@end
ChildClass.h
// cela importera BaseClass.h sans l'extension de classe
#import "BaseClass.h"
@interface ChildClass : BaseClass
-(void)test;
@end
ChildClass.m
// cela importera implicitement BaseClass.h depuis ChildClass.h,
// avec BaseClass_protected défini,
// donc cela inclura également l'extension de classe protégée
#define BaseClass_protected
#import "ChildClass.h"
@implementation ChildClass
-(void)test {
self.foo = @"test";
self.bar = 123;
[self baz];
}
@end
Lorsque vous appelez #import
, cela revient essentiellement à copier-coller le fichier .h à l'endroit où vous l'importez. Si vous avez un #ifdef
, cela inclura uniquement le code à l'intérieur si le #define
avec ce nom est défini.
Dans votre fichier .h, vous ne définissez pas le #define donc les classes important ce .h ne verront pas l'extension de classe protégée. Dans le fichier .m de la classe de base et de la sous-classe, vous utilisez #define
avant d'utiliser #import
pour que le compilateur inclue l'extension de classe protégée.