9

最近 Xcode 4.3.2 に更新したところ、次@implementationのようにブロック内でプライベート インスタンス変数を宣言できるようになりました。

@interface TestClass : NSObject
@property (nonatomic, copy) NSString *testProp;
@end

@implementation TestClass {
    NSString *_testPropStore;
}

- (NSString *)testProp { return _testPropStore; }
- (void)setTestProp:(NSString *)testProp { _testPropStore = [testProp copy]; }

- (id)init {
    if (self = [super init]) {
        _testPropStore = nil;
    }
    return self;
}

@end

ブレース ブロックNSString *_testPropStore内の行に注目してください。@implementation

次のコードでもテストしました。

TestClass *c1 = [[TestClass alloc] init];
TestClass *c2 = [[TestClass alloc] init];

c1.testProp = @"Hello";
c2.testProp = @"World";

NSAssert(c1.testProp == c2.testProp, @"It's working!");

これはうまくいくようです。(つまり、アプリは NSAssert 行で「動作しています」というメッセージでクラッシュします。)

これは、プライベート インスタンス変数を宣言するための Objective-C の新機能ですか? 私は偶然これを発見したので、プライベートインスタンス変数を宣言するためだけのものなのか、それとも私が気付いていない副作用があるのか​​知りたいです?

そのようなタイプの単語を含むほとんどの質問は、private異なるプライベート拡張カテゴリでそれらを宣言する方法についての回答になってしまったため、関連するドキュメントを見つけることができませんでした。

4

2 に答える 2

19

それは本当です、それは新しい方法です*それは素晴らしいです、そして、そうです、それはドキュメントにあります. Objective-C プログラミング言語は、言語の実際の仕様を持つのと同じくらい近いですが、次のように述べています。

クラスの定義は、その宣言と非常によく似た構造になっています。ディレクティブで始まり、@implementationディレクティブで終わり@endます。さらに、クラスは@implementationディレクティブの後に中括弧でインスタンス変数を宣言できます。

@implementation ClassName
{
    // Instance variable declarations.
}
// Method definitions.
@end

そのリンクから少しさかのぼる歴史的なメモもあり、以前はインターフェイス ブロックで ivar を宣言する必要があったという事実に対処しています。

歴史的に、インターフェイスは、クラスのインスタンス変数 (クラスの各インスタンスの一部であるデータ構造) の宣言を必要としていました。... インスタンス変数は実装の詳細を表し、通常はクラス自体の外からアクセスするべきではありません。さらに、実装ブロックで宣言するか、宣言されたプロパティを使用して合成できます。したがって、通常、パブリック インターフェイスでインスタンス変数を宣言しないでください。そのため、中かっこを省略してください。

@privateプライバシーの問題については、はい、これらの変数は真にプライベートです。ディレクティブとのインターフェイスで宣言された ivar のように機能します。これは、デフォルトでは、サブクラスがそれらにアクセスできないことを意味します。ただし、これらの可視性は、@protectedまたは (何らかの奇妙な理由で必要な場合) を使用して変更でき@publicます。

@interface Stuper : NSObject 
@end

@implementation Stuper
{
    @protected
    NSString * sangfroid;
}
@end

@interface Stub : Stuper
- (void)setSangfroid: (NSString *)newSangfroid;
@end

@implementation Stub

- (void)setSangfroid: (NSString *)newSangfroid {
    sangfroid = [newSangfroid copy];
}

*clang > 3.0 を使用する必要があると思います。これは、この投稿の時点でほんの数か月前のことです。GCCはそれをしません。

于 2012-05-02T04:49:56.260 に答える
2

これはかなり新しいものであり、必要なコンパイラがサポートしている限り有効です。

依存関係を最小限に抑えるのに最適です。インクルードと転送の大部分は実装ファイルに含まれている可能性があります。このため、使用するすべてのコンパイラがそれをサポートしている場合、ivar は@interfaceブロック内よりも適切な場所です。

最後の注意点として、現在 (2012 年 5 月 2 日) のデバッガーはこれをサポートしていません。

于 2012-05-02T04:49:36.940 に答える