1

xcode 4.4以降、プロパティを作成する必要がなくなったため@synthesizeここを参照)、コンパイラが自動的にプロパティを実行します。では、なぜコンパイラは文句を言うのですか?

宣言されていない識別子_aVarの使用

私のviewDidLoad方法でViewControllerSubclass

@interface ViewController : UIViewController
@property (assign, nonatomic) int aVar;
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.aVar = 5;
    NSLog(@"Super value: %d", _aVar);
}
@end

@interface ViewControllerSubclass : ViewController
@end

@interface ViewControllerSubclass ()
@property (assign, nonatomic) int aVar;
@end

@implementation ViewControllerSubclass
- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"Subclass value: %d", _aVar);
}
@end

それぞれのインターフェースと実装のために4つの別々のファイルではなく、すべてを1つのファイルに移動すると、コンパイラーは代わりにそれ_aVarがプライベートであると文句を言います。しかし、_aVarは私ので自動的に合成されるべきでしたViewControllerSubclass

最初のプロパティ宣言をクラス拡張子に移動した場合でも、すべてを1つのファイルに保持します。

@interface ViewController ()
@property (assign, nonatomic) int aVar;
@end

_aVarビルドはまだプライベートであると言って失敗します。

それぞれのインターフェースと実装の4つのファイル設定に戻ると、警告なしでxcodeがビルドされます。

次にコードを実行すると、次のようになります。

[[[ViewControllerSubclass alloc] init] view];

上記の例のログステートメントは、次のように出力します。

スーパー値:0

サブクラス値:5

この変数はスーパークラスにプライベートであると想定されているためNSLog(@"Super value: %d", _aVar);、結果を生成したことは理にかなっています。0しかし、なぜ??NSLog(@"Subclass value: %d", _aVar);の結果を生成するのですか?5

これはすべて非常に奇妙です。

4

3 に答える 3

6

あなたはいくつかの異なる問題を混乱させています.ファイル間のジャンプについて話し、エラーがどこで発生したかを指定しないと、私はやや混乱します.

とにかく、インスタンス変数の可視性の問題があります。インターフェイス スコープ内で iVar を宣言すると、デフォルトで保護されます。

@interface Foo : NSObject {
    int protectedInt;
@private
    int privateInt;
@public
    int publicInt;
}
@end

iVar を合成すると、明示的に指定しない限り、インスタンス変数自体はプライベートになります。

メソッドは常に、最も派生した実装で起動します。

さて、これを呼び出すと...

[[[ViewControllerSubclass alloc] init] view];

サブクラスを割り当て、初期化し、ビューをロードします。このコードは実行されます...

@implementation ViewControllerSubclass
- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"Subclass value: %d", _aVar);
}
@end

最初に行うことは、基本クラスの実装を呼び出すことです...

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.aVar = 5;
    NSLog(@"Super value: %d", _aVar);
}
@end

もちろん、それは super を呼び出しますが、その部分はここでは重要ではありません。次の行は、self.iVar に 5 を割り当てます。しかし、どのiVarですか?このオブジェクトのプロパティ セッターメソッドを呼び出します。このインスタンスはどのタイプですか? それはViewControllerSubclassです。基本クラスとそのサブクラスの両方に同じ名前を付けた (そしてクラス拡張の一部としてプロパティを宣言した) ため、それぞれに独自のプライベート スコープのインスタンス変数があります。

ただし、最も派生した実装でメソッドが呼び出されます。したがって、self.iVar はサブクラスのインスタンス変数を設定します。基本クラスのインスタンス変数は変更されません。

値を取得するとNSLog、変更されていない基本クラスのプライベート インスタンス変数にアクセスします。

基本クラスviewDidLoadが終了したら、サブクラスのコードを実行します。プロパティ セッターを呼び出した基本クラスの結果として変更されたプライベート インスタンス変数の値をログに記録します。そのため、値が 5 と表示されます。

于 2012-08-26T14:26:36.907 に答える
5

スーパークラス宣言を public にすると、コンパイラはプロパティの再合成を試みません。スーパークラスで処理されていることを前提としています。したがって、_aVarサブクラスのどこにもスコープがありません。とにかくプライベートなので、それらをすべて同じファイルに入れても、エラーが表示されるのはそのためです。

ただし、クラス拡張内でスーパークラスのプロパティ宣言を行うと、コンパイラはスーパークラスとサブクラスの両方のプロパティを自動合成します。これにより、両方のクラスがプライベート インスタンス変数 _aVar (2 つの異なるアドレスを持つ) を持つことになります。ただし、スーパークラスviewDidLoadメソッドがプロパティを設定すると、メソッドはサブクラスのアクセサーを呼び出します。このアクセサーは、スーパークラスの値ではなく、サブクラスのプライベート _aVar 変数の値を設定します。これで、スーパークラスの値が変化しない理由がわかります。

お役に立てれば!

于 2012-08-26T14:25:12.900 に答える
0

セットアップをテストしたところ、エラーを再現できました。私は次の結論に達しました。

@propertyファイルで宣言する必要があり.hます。プライベート変数が必要な場合.mは、カテゴリ@interface(かっこのあるもの) で宣言します。

于 2012-08-26T12:43:33.273 に答える