これは、基本クラスとサブクラスの両方の実装ファイルに含めるクラス拡張 (カテゴリではない) を使用することで可能になります。
クラス拡張はカテゴリと同様に定義されますが、カテゴリ名はありません:
@interface MyClass ()
クラス拡張では、バッキング ivar を合成できるプロパティを宣言できます (XCode > 4.4 ivar の自動合成もここで機能します)。
拡張クラスでは、プロパティをオーバーライド/調整し (readonly を readwrite に変更するなど)、実装ファイルに「表示」されるプロパティとメソッドを追加できます (ただし、プロパティとメソッドは実際には非公開ではないことに注意してください。まだセレクターによって呼び出されます)。
他の人は、これに別のヘッダー ファイル MyClass_protected.h を使用することを提案していますが、これは次の#ifdef
ように使用してメイン ヘッダー ファイルで行うこともできます。
例:
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
を呼び出すと#import
、基本的に .h ファイルをインポート先にコピーして貼り付けます。がある場合、その名前の が設定されている#ifdef
場合にのみコードが含まれます。#define
.h ファイルでは定義を設定しないため、この .h をインポートするクラスは保護されたクラスの拡張を認識しません。基本クラスとサブクラスの .m ファイルでは、使用する#define
前に使用#import
して、コンパイラが保護されたクラス拡張を含めるようにします。