2012-05-02 10 views
9

は、私は最近、Xcodeの4.3.2にアップデートして、私は今とても似@implementationブロック内のプライベートインスタンス変数を宣言することができることを発見しました:Objective-Cでプライベートインスタンス変数を定義する新しい方法ですか?

@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行の "It's working"メッセージでクラッシュします)。

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

privateというようなタイプの質問のほとんどが、異なる私的な拡張カテゴリでそれらを宣言する方法についての回答に終わったため、関連するドキュメントが見つかりませんでした。

答えて

19

これは本当の意味で、新しい方法です。素晴らしいことですが、はい、ドキュメントにあります。

をクラスの定義は、その宣言のように非常に構造化されています。私たちは、言語の実際の仕様を持つに着くほど近くにあるThe Objective-C Programming Languageは、言って、次があります。 @implementationディレクティブで始まり、@endディレクティブで終わります。また、クラスが@implementationディレクティブの後にカッコでインスタンス変数を宣言することがあります。我々はアイバーズを宣言するために持っていたという事実に対処し、バックリンクしているページからの履歴ノートにも少し方法をあります

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

インタフェースブロック:

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

これらの変数は本当にプライベートです。つまり、@privateディレクティブとのインターフェイスで宣言されたivarsのように動作します。つまり、デフォルトでは、サブクラスはアクセスできません。彼らの視認性が@public(必要に応じていくつかの奇妙な理由で)@protectedかのいずれかを使用して、しかし、変更することができます:それはほんの数ヶ月ですので

@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]; 
} 

*あなたが打ち鳴らす> 3.0を使用する必要があり、私は、信じていますこの投稿の前にGCCはそれをしません。

+0

私は、これがどのようにボンネットの下で行われているのか、より興味があります。ヘッダーに不完全な定義がある場合、Objective-Cランタイムはクラスに割り当てるメモリの量をどのように知っていますか? – mpontillo

+0

それは投稿するのが大変な質問です。それはほぼ確実に["非脆弱なイナール"(http://www.sealiesoftware.com/blog/archive/2009/01/27/objc_explain_Non-fragile_ivars.html)と関係があります。 –

+0

参考までに、あなたの答えのリンクが壊れているようです。 –

2

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

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

最新の注意点は、現在の(may.2.2012)デバッガがこれをサポートしていないことです。

+2

デバッガについての非常に良い点。これに関する小さなスレッドがlldb.develリストにあります:http://comments.gmane.org/gmane.comp.debugging.lldb.devel/624 –

関連する問題