15

私はiOS 6アプリの構築に取り組んでいます。

スーパークラスTDWeaponから継承するクラス TDBeam があります

スーパークラスTDWeaponは、TDWeapon.h ファイルで @property を宣言します。

@interface TDWeapon : UIView

@property (nonatomic) int damage;

@end

プロパティを明示的に @synthesize しません。Xcode に自動的に行わせるためです。

サブクラスTDBeamで、TDBeam.m ファイルの getter をオーバーライドします。

#import "TDBeam.h"

@implementation TDBeam

- (int)damage {
    return _damage;
}

@end

予想どおり、Xcode は getter メソッド名をオートコンプリートします。しかし、_damage インスタンス変数 (スーパークラスから継承) を参照しようとすると、コンパイラ エラーが発生します。

Use of undeclared identifier '_damage'

ここで何が間違っていますか?@synthesize を明示的に追加し、_damage ivar の名前を変更しようとしましたが、コンパイラはそれまたはスーパークラスの他の ivar を「認識」しません。サブクラスから ivar が表示され、アクセスできると思いましたか?

4

2 に答える 2

21

合成されたivarは、明示的に作成されたか自動的に作成されたかに関係なく、サブクラスには表示されません。@synthesizedインスタンス変数の表示はどのようになりますか?それらは実装ファイルで効果的に宣言されているため、それらの宣言はサブクラスを含む「翻訳ユニット」には含まれていません。

そのivarに直接アクセスしたい場合は、プライベートヘッダーのスーパークラスのクラス拡張など、サブクラスが参照できる場所で明示的に宣言する必要があります(デフォルトの「保護された」形式で)。

于 2012-10-28T22:02:25.770 に答える
2

スタック オーバーフローに関するこのトピックに関する投稿はたくさんありますが、単純で具体的なアドバイスを提供するものはありませんが、このトピックはそれを最も簡潔にまとめており、Josh の回答はどの投稿よりも優れています。

彼が率直に言ってやめていることは、もしこれがあなたがやりたいことであるなら、@property をまったく使わないということです。彼が言うように、基本クラスで通常の保護された変数を宣言し、必要に応じて独自のセッターとゲッターであると記述します。ivar は、独自のセッター/ゲッターを作成できるすべてのサブクラスに表示されます。

私はサブクラス化に完全に慣れていませんが、少なくともそれが私がこの問題にたどり着いた場所です。

匿名カテゴリをホストするプライベート ヘッダーを作成し、サブクラスで ivar を再 @sythesizing するという考えは、非常に多くのレベルで間違っているように思えます。また、おそらくどこかで基本的な点を見逃していると確信しています。


編集

睡眠不足の後、スタンフォード大学の 2013 年 iTunes U コースに触発されて、ここにこの問題の解決策の例があると思います。

MYFoo.h

#import <Foundation/Foundation.h>

@interface MYFoo : NSObject
// Optional, depending on your class
@property (strong, nonatomic, readonly) NSString * myProperty;
- (NSString *)makeValueForNewMyProperty; //override this in your subclass
@end

MYFoo.m

#import "MYFoo.h"

@interface MYFoo ()
   @property (strong, nonatomic, readwrite) NSString * myProperty;
@end

@implementation MYFoo
// Base class getter, generic
- (NSDateComponents *)myProperty {
    if (!_myProperty) {
        _myProperty = [self makeValueForNewMyProperty];
    }
    return _myProperty;
}


// Replace this method in your subclass with your logic on how to create a new myProperty
- (NSString *)makeValueForNewMyProperty {
    // If this is an abstract base class, we'd return nil and/or throw an exception
    NSString * newMyProperty = [[NSString alloc]init];
    // Do stuff to make the property the way you need it...
    return newMyProperty;
}

@end

次に、サブクラスの makeValueForNewMyProperty を必要なカスタム ロジックに置き換えるだけです。プロパティは基本クラスで「保護」されていますが、作成方法を制御できます。これは、ほとんどの場合、基本的に達成しようとしていることです。

makeValueForNewMyProperty メソッドが基本クラスの他の ivar へのアクセスを必要とする場合、それらは少なくともパブリックな読み取り専用プロパティ (または単なるネイキッド ivar) である必要があります。

正確に「ゲッターをオーバーライドする」わけではありませんが、少し考えれば、同じようなことを達成できます。例を一般的なものにしようとして、優雅さと明快さが失われてしまったことをお詫びします。

于 2013-02-07T09:44:09.730 に答える