このクラスを定義している場合、コンパイラエラーなしでサブクラスのsomeObject
プロパティにアクセスするにはどうすればよいですか?
@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
明らかに、objective-cでの継承の仕組みを理解していません。誰かが私を啓発できますか?
解決策は、クラス拡張でMyBaseClassプライベートプロパティを宣言することです。
@interface MyBaseClass ()
@property (nonatomic, readwrite, retain) NSObject *someObject;
@end
その宣言を自由に作成できます両方 MyBaseClassでおよび MySubclassで。これにより、MySubclassがこれらのプロパティを認識できるようになり、そのコードがそれらについて話すことができます。
繰り返しが気になる場合は、クラス拡張子を独自の.hファイルに入れて、両方の.mファイルにインポートします。
私は自分のコードから例を挙げます。 MyDownloaderPrivateProperties.h:
@interface MyDownloader ()
@property (nonatomic, strong, readwrite) NSURLConnection* connection;
@property (nonatomic, copy, readwrite) NSURLRequest* request;
@property (nonatomic, strong, readwrite) NSMutableData* mutableReceivedData;
@end
対応する。mファイルはなく、このファイルにあるのはそれだけです。それは、いわば純粋に宣言的なものです。これがMyDownloader.mの始まりです。
#import "MyDownloader.h"
#import "MyDownloaderPrivateProperties.h"
@implementation MyDownloader
@synthesize connection=_connection;
@synthesize request=_request;
@synthesize mutableReceivedData=_mutableReceivedData;
// ...
そして、ここにそのサブクラスの始まりがありますMyImageDownloader.m:
#import "MyImageDownloader.h"
#import "MyDownloaderPrivateProperties.h"
問題が解決しました。 MyDownloaderPrivateProperties.hをインポートする唯一のクラスであるため、プライバシーは保持されます。したがって、コンパイラに関する限り、これらのプロパティについて知っている唯一のクラスです(そして、それがObjective- C)。サブクラスは、アクセサがスーパークラスによって合成されるプライベートプロパティにアクセスできます。それがあなたがそもそも達成したかったことだと思います。
それはあなたがそれらにアクセスする方法です。あなたがそれらを宣言する方法はあなたを噛んでいるものです:
@interface MyBaseClass : NSObject
@property (nonatomic, readwrite, retain) NSObject *someObject;
@end
これは、新しいobjcクラスを宣言する通常の方法です。
括弧を追加することにより(この場合はNSObjectを宣言する代わりに)、クラス拡張を宣言しました。これはおそらくサブクラスからは見えません(包含を介して)。
objcでルートクラスを宣言する必要はおそらくないでしょう。
@interface MyBaseClass // << superclass omitted
@property (nonatomic, readwrite, retain) NSObject *someObject;
@end
NSObject(またはAppleのシステムをターゲットとする場合のサブクラス)は、経験が豊富でルートクラスの目的がわからない限り、基本クラスになります。
クラス拡張は、プライベートインターフェイスを「シミュレート」するためによく使用されます。シミュレートすることにより、コンパイラはこれを強制しません。他の言語で強制されるためです。たとえば、同じセレクタで宣言された場合、サブクラスは拡張機能のメソッドを(知らないうちに)オーバーライドする可能性がありますが、すべてのメッセージは依然として動的です。
基本クラス名の後の()から判断すると、クラス実装内でプライベートインターフェイス拡張を宣言しているように見えますが、これは事実ですか?その場合、変数はそのクラス実装内からのみアクセス可能になります。
MyBaseClass
はNSObjectから直接継承しますか?
その場合、次のように、インターフェイスファイルでsomeObject
プロパティを宣言する必要があります。
@interface MyBaseClass : NSObject
{
}
@property (nonatomic, retain) NSObject *someObject;
そして、あなたがすでにやっているようにそれを合成します。
これは、ほとんどの目的を満たす代替手段です。
ヘッダーで、インターフェースを定義します
@interface MyBaseClass : NSObject {
NSObject *inheritableObject;
}
@property (readonly) NSObject *inheritableObject;
MyBaseClassおよびMyBaseClassを継承する任意のクラスでinheritableObjectを編集できるようになりました。ただし、外部からは読み取り専用です。 @interface MyBaseClass()の場合のようにプライベートではありませんが、制御されない変更から保護されています。