Ceci est possible en utilisant une extension de classe (pas de catégorie) que vous incluez dans les fichiers de mise en œuvre à la fois la classe de base et les sous-classes.
Une extension de classe est définie similaire à une catégorie, mais sans le nom de la catégorie:
@interface MyClass()
Dans une extension de classe, vous pouvez rapporter des propriétés, qui sera en mesure de synthétiser les Ivars d'appui (XCode> 4.4 la synthèse automatique des ivars fonctionne également ici). Dans la classe d'extension, vous pouvez remplacer/affiner les propriétés (modifier readonly en readwrite, etc.) et ajouter des propriétés et des méthodes qui seront "visibles" aux fichiers d'implémentation (mais notez que les propriétés et les méthodes ne sont pas vraiment privé et peut encore être appelé par le sélecteur).
D'autres ont proposé d'utiliser un fichier séparé d'en-tête MyClass_protected.h pour cela, mais cela peut aussi être fait dans le fichier principal d'en-tête en utilisant #ifdef
comme ceci:
Exemple:
BaseClass.h
@interface BaseClass : NSObject
// foo is readonly for consumers of the class
@property (nonatomic, readonly) NSString *foo;
@end
#ifdef BaseClass_protected
// this is the class extension, where you define
// the "protected" properties and methods of the class
@interface BaseClass()
// foo is now readwrite
@property (nonatomic, readwrite) NSString *foo;
// bar is visible to implementation of subclasses
@property (nonatomic, readwrite) int bar;
-(void)baz;
@end
#endif
BaseClass.m
// this will import BaseClass.h
// with BaseClass_protected defined,
// so it will also get the protected class extension
#define BaseClass_protected
#import "BaseClass.h"
@implementation BaseClass
-(void)baz {
self.foo = @"test";
self.bar = 123;
}
@end
ChildClass.h
// this will import BaseClass.h without the class extension
#import "BaseClass.h"
@interface ChildClass : BaseClass
-(void)test;
@end
ChildClass.m
// this will implicitly import BaseClass.h from ChildClass.h,
// with BaseClass_protected defined,
// so it will also get the protected class extension
#define BaseClass_protected
#import "ChildClass.h"
@implementation ChildClass
-(void)test {
self.foo = @"test";
self.bar = 123;
[self baz];
}
@end
Lorsque vous appelez #import
, il copie des pâtes essentiellement le fichier .h à l'endroit où vous l'importer. Si vous avez un #ifdef
, il 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 la définition de manière à ce que les classes qui importent ce fichier .h ne voient 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
afin que le compilateur inclue l'extension de classe protégée.
Pour être "protégée", l'interface d'extension de classe doit se trouver dans un fichier d'en-tête distinct à inclure dans la classe et ses sous-classes. – JeremyP
Pour autant que je sache, toutes les propriétés déclarées dans l'extension d'interface de classes de base ne sont pas disponibles pour les sous-classes - elles ont une portée privée, non protégée. Voir cette discussion SO: http://stackoverflow.com/questions/5588799/objective-c-how-do-you-access-parent-properties-from-subclasses – memmons
@Harkonian si vous déclarez le sélecteur vous-même, vous pouvez toujours appeler il. Il n'y a pas de «protection» d'une méthode autre que le simple fait de cacher sa déclaration. Objective-C n'a pas le concept de méthodes protégées ou privées. Seulement ivars protégés ou privés. –