web-dev-qa-db-ja.com

合成された読み取り専用プロパティを持つクラスのサブクラスは、Objective-Cのインスタンス変数にアクセスできません

スーパークラスではMyClass

@interface MyClass : NSObject

@property (nonatomic, strong, readonly) NSString *pString;

@end

@implementation MyClass

@synthesize pString = _pString;

@end

サブクラス内MySubclass

@interface MySubclass : MyClass

@end

@implementation MySubclass

- (id)init {
    if (self = [super init]) {
        _pString = @"Some string";
    }
    return self;
}

問題は、コンパイラが_pStringMySubclassのメンバーですが、MyClassで問題なくアクセスできます。

何が足りないのですか?

26

_pStringによって生成されるインスタンス変数@synthesizeは、private to MyClassです。 MySubclassがアクセスできるようにするには、protectedにする必要があります。

次のように、MyClass_pStringセクションに@protectedのivar宣言を追加します。

@interface MyClass : NSObject {
    @protected
    NSString *_pString;
}

@property (nonatomic, strong, readonly) NSString *pString;

@end

ここで、通常どおりアクセサーを合成すると、変数がサブクラスにアクセスできるようになります。

54
dasblinkenlight

私はこの問題に精通しています。 .mクラスで変数を合成します。これは、_pString変数がインターフェイスではなく実装の一部として作成されるため、ヘッダーと一緒にインポートされないためです。解決策は、ヘッダーインターフェイスで_pStringを宣言し、それをとにかく合成することです(プライベート変数を作成する代わりに、既存の変数を使用します)。

@interface MyClass : NSObject
{
    NSString *_pString; //Don't worry, it will not be public
}

@property (nonatomic, strong, readonly) NSString *pString;

@end
5
borrrden

与えられた答えは完全にうまく機能します。これは別の答えであり、明らかにApple もう少し好きです

クラスの プライベート拡張子MyClass+Protected.hファイルを定義できます。これは、MyClass.mおよびMySubclass.mに含める必要があります。

次に、この新しいファイルで、プロパティをreadwriteとして再定義します。

@interface MyClass ()
@property (strong, readwrite) NSString * pString;
@end

この代替手段では、ivar self.pStringではなくアクセサー_pStringを使用できます。

注:pStringの定義をMyClass.hにそのまま保持する必要があります。

0
Fabricio PH