web-dev-qa-db-ja.com

Objective-C:サブクラスから親プロパティにどのようにアクセスしますか?

このクラスを定義している場合、コンパイラエラーなしでサブクラスの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での継承の仕組みを理解していません。誰かが私を啓発できますか?

44
memmons

解決策は、クラス拡張で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)。サブクラスは、アクセサがスーパークラスによって合成されるプライベートプロパティにアクセスできます。それがあなたがそもそも達成したかったことだと思います。

54
matt

それはあなたがそれらにアクセスする方法です。あなたがそれらを宣言する方法はあなたを噛んでいるものです:

@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のシステムをターゲットとする場合のサブクラス)は、経験が豊富でルートクラスの目的がわからない限り、基本クラスになります。

クラス拡張は、プライベートインターフェイスを「シミュレート」するためによく使用されます。シミュレートすることにより、コンパイラはこれを強制しません。他の言語で強制されるためです。たとえば、同じセレクタで宣言された場合、サブクラスは拡張機能のメソッドを(知らないうちに)オーバーライドする可能性がありますが、すべてのメッセージは依然として動的です。

14
justin

基本クラス名の後の()から判断すると、クラス実装内でプライベートインターフェイス拡張を宣言しているように見えますが、これは事実ですか?その場合、変数はそのクラス実装内からのみアクセス可能になります。

MyBaseClassはNSObjectから直接継承しますか?

その場合、次のように、インターフェイスファイルでsomeObjectプロパティを宣言する必要があります。

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

そして、あなたがすでにやっているようにそれを合成します。

4
Rog

これは、ほとんどの目的を満たす代替手段です。

ヘッダーで、インターフェースを定義します

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

MyBaseClassおよびMyBaseClassを継承する任意のクラスでinheritableObjectを編集できるようになりました。ただし、外部からは読み取り専用です。 @interface MyBaseClass()の場合のようにプライベートではありませんが、制御されない変更から保護されています。

0
Hans Bot