2011-11-20 3 views
23

職場でのプロパティとインスタンス変数の使用に関する議論がありましたので、そのためのwikiの回答を探したいと思います。さて、私は客観的にprivateなメンバー型がないことを知っています.c全てがかなり公表されています。しかし、私はクラスをデザインし、OOPの原則に準拠する方法について少しは心配しています。私的なメンバーと公的なメンバーは、どのように客観的に実装されるべきですか?

A.様々な投稿や新しいスタンフォード大学のiPhone開発コースによれば、できる限りの場所で常にプロパティを使用する必要があります。しかし、IMHOでは、このアプローチはOOP設計原則を制動します。この場合、すべてのメンバーが公開されるからです。内部/ローカルのインスタンス変数をすべて外部に公開する必要があるのはなぜですか?また、ローカルのivarを直接使用する代わりに、プロパティを介して合成されたsetterを使用すると、ごくわずかな(ただしまだ)オーバーヘッドがあります。

//==== header file =====// 
@interface MyClass : NSObject 

@property (nonatomic, retain) NSString *publicMemberWithProperty; 
@property (nonatomic, retain) NSString *propertyForPrivateMember; 

@end 

B.別のアプローチは、プライベートメンバーの(相対的なプロパティを宣言せず)ヘッダファイルにアイバーズを宣言し、同じヘッダファイルで、(相対アイバーズを宣言せずに)純粋なプロパティを宣言することである:ここでサンプルですパブリックメンバー。そのような場合には、イナバルがクラス内で直接使用されます。この方法は理にかなっていますが、新しい値を設定する前に古い値を手動で解放する必要があるため、プロパティのすべての利点を使用しません。

//==== header file =====// 
@interface MyClass : NSObject{ 
    NSString *_privateMember; 
} 

@property (nonatomic, retain) NSString *publicMemberWithProperty; 

@end 

C.は、ヘッダファイルのパブリックメンバーの(相対アイバーズを宣言せずに)純粋なプロパティを宣言し、実装ファイルにプライベートインターフェイスでプライベートメンバーの(相対アイバーズを宣言せずに)純粋なプロパティを宣言する:ここでサンプルです。このアプローチは最初のIMHOよりもはっきりしていますが、同じ質問が残っています。なぜ内部/ローカルメンバーのプロパティを持つ必要がありますか?ここではサンプルです:

//==== header file =====// 
@interface MyClass : NSObject 

@property (nonatomic, retain) NSString *publicMemberWithProperty; 

@end 

//==== implementation file =====// 
@interface MyClass() 

@property (nonatomic, retain) NSString *propertyForPrivateMember; 

@end 

この決定の自由度は私に少し不愉快にさせると私は物事が行われるべきかについてのそれぞれの供給源からの確認を見つけるしたいと思います。しかし、私はApple docsにそのような厳しい声明を見つけることができませんでした。もしあればapple docsへのリンクやそれをクリアする他の理論に投稿してください。

+0

この質問は非常に主観的で、正しい方法で答えるのは不可能だと思われます。 – Till

+0

質問は非常に簡単です。つまり、私的なメンバーと公的なメンバーを客観的にどのように実装すればよいのでしょうか。 – Centurion

+1

私は異なっていると思っていますが、議論を深めません。あなたの主張を証明するためのヒントとして、 Stanfordコースではあらゆる場所でプロパティを使用することをお勧めします。 – Till

答えて

21

クラス拡張を使用すると、プライベートプロパティを持つことができます。

クラス拡張構文は単純です:

の.h

@interface OverlayViewController : UIViewController <VSClickWheelViewDelegate> 
- (IBAction)moreButtonClicked:(id)sender; 
- (IBAction)cancelButtonClicked:(id)sender; 
@end 

.M:

クラスを持っている.M-ファイル、インサイド

は、無名のカテゴリを作成します

#import "OverlayViewController.h" 

@interface OverlayViewController() 
@property(nonatomic) NSInteger amount; 
@property(retain,nonatomic)NSArray *colors; 
@end 

@implementation OverlayViewController 
@synthesize amount = amount_; 
@synthesize colors = colors_; 

//… 

@end 

プライベートメンバーのプロパティのすべての側面を公開しました。コンパイラーは、コンパイル時に多かれ少なかれ同じものを作成するため、作成されたゲッター/セッターに合成プロパティーのオーバーヘッドはありません。

このコードでは合成されたイヴァールが使用されています。ヘッダーにivar宣言は必要ありません。

このアプローチについては、cocoawithlove articleがあります。

プライベートイーバールのプロパティを使用する理由も尋ねます。いくつかの理由があります。

  • プロパティは所有権とメモリ管理に注意してください。
  • 将来的には、カスタムゲッター/セッターを書くことができます。 NSArray ivarが新たに設定されると、テーブルビューをリロードする。結果としてプロパティを使用した場合、他の変更は必要ありません。
  • キー値コーディングサポートのプロパティ。
  • public readonly properties can be re-declared to private readwrite properties.

編集
LLVM 3以降では、クラスの拡張

@interface OverlayViewController(){ 
    NSInteger amount; 
    NSArray *colors; 
} 
@end 

かさえ実装ブロックで

@implementation OverlayViewController{ 
    NSInteger amount; 
    NSArray *colors; 
} 
//… 
@end 

ご覧にアイバーズを宣言することも可能です"WWDC2011:Session 322 - Objective-C Advancemen ts in Depth "(〜03:00)

+0

コンパイラの警告を勇気づけるなら、getterとsetterは他のコードでも使用できるので、これらは厳密にはprivateではありませんが、コンパイラの警告が他の人に警告するのに十分です。私のチームでインスタンス変数の宣言が必要です。私が適用するルールは、ヘッダーファイル内のすべてが定義上publicであるということです。 – Tommy

+0

@ Tommy:私の仕事では、プライベートメンバーのためにプロパティを宣言して使用する必要がある理由がいくつかありました。彼らは、純粋なインスタンス変数を使用し、クラスコードで直接使用するべきだと述べました。これを行う動機は、古い値を手動で解放し、新しいvalを直接ivarに割り当てる代わりに、setterを使用するときの処理オーバーヘッドがあることです。ちょうど興味があるのは、その上にAppleの "推奨"声明がありますか? – Centurion

+0

@Centurion「プライベート」プロパティを使用して[メモリ管理を簡単にする]ことができます(http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html#//apple_ref/doc/uid/TP40004447-SW4): "時には退屈で賢明なように見えるかもしれませんが、アクセサーメソッドを一貫して使用するとメモリ管理に問題が生じる可能性はかなり低くなります。コード、あなたは間違ったことをほぼ確実にやっている」 – albertamg

2

C++と同様に、Objective Cはパブリック、プライベート、および保護されたスコープを提供します。また、Javaで定義されているパッケージスコープと同様のパッケージスコープも提供します。 クラスのパブリック変数は、プログラム内のどこでも参照できます。 プライベート変数は、それを宣言するクラスのメッセージ内でのみ参照できます。これは、同じクラスの任意のインスタンスに属するメッセージ内で使用できます。 パッケージスコープは、同じイメージ、つまり実行可能ファイルまたはライブラリ内のパブリックスコープと似ています。 Appleの文書によると、64ビットアーキテクチャでは、別のイメージ内で定義されたパッケージスコープの変数は非公開として扱われます。 可変スコープは@public、@private、@protected、@package修飾子で定義されています。これらの修飾子は、C++やJavaのような方法で使用できます。スコープ宣言の下にリストされたすべての変数は同じスコープに属します。また、スコープが宣言されている行と同じ行に変数をリストすることもできます。詳細情報については

@interface VariableScope : NSObject { 
     @public 
     int iVar0; 
     @protected 
     int iVar1; 
     @private 
     int iVar2; 
     @package 
     int iVar3; 

@public int iVar01, iVar02; 
@protected int iVar11, iVar12; 
@private int iVar21, iVar22; 
@package int iVar31, iVar32; 
} 
    @end 

本当に直接の言語でサポートされ、これに清潔、安全、ゼロオーバーヘッド、解決策ありません

http://cocoacast.com/?q=node/100

+4

はい、パブリック、プライベート、保護などのキーワードがありますが、ランタイム中に範囲を制限しません。私はいくつかのテストを行いました。客観的に言えば、すべてのメンバーがかなり公表されています。私の実験に関する記事は、ここで見つけることができます:http://stackoverflow.com/questions/6122398/objective-c-why-private-ivars-are-not-hidden-from-the-outside-access-when-using – Centurion

3

下のリンクを使用します。多くの人々は現在の可視性の特徴に満足していますが、多くの人々は不足していると感じています。

ランタイムとすることができますが、ivarsやメソッドと区別します。ファーストクラスのサポートは、IMOが最適です。 - すべての目に見える

が悪い

オプション:それまでは、我々はいくつかの抽象化イディオムを持っています。私はそれが良いアプローチであり、OOD(IMO)ではないことに同意しない。すべての場合、クライアントは

  • (通常は不合理または望ましくない)あなたのクラスを使用する方法のためか、文書(ドキュメント経由ルールのトンとそれらを提供

    • サポート:すべてが表示されている場合は、あなたのクラスは、どちらかのはずアップデートは)
    • を気付かれない可能性があるか、アクセサはOODを(副作用がないではないはずであり、頻繁に

    オプションB)「アクセサをオーバーライドしない」に変換さ

    オプションAの欠点を持ちますが、オプションAと同様、メンバーはキーでアクセスできます。

    オプションCこれは少し安全です。すべての他のものと同様に、あなたは引き続き鍵付きアクセスを使用することができ、サブクラスは(たとえ無意識にでも)あなたのアクセサを上書きすることがあります。これに

    オプションD

    一つのアプローチは、実装タイプの上にオーバーラッパーとしてあなたのクラスを記述することです。これにはObjC型またはC++型を使用できます。あなたはスピードが重要なC++を好むかもしれません(それはOPで言及されています)。

    これに対する単純なアプローチは、のいずれかの形式を取るだろう:(

    // inner ObjC type 
    @class MONObjectImp; 
    
    @interface MONObject : NSObject 
    { 
    @private 
    MONObjectImp * imp; 
    } 
    @end 
    
    
    // Inner C++ type - Variant A 
    class MONObjectImp { ... }; 
    
    @interface MONObject : NSObject 
    { 
    @private 
    MONObjectImp imp; 
    } 
    @end 
    
    
    // Inner C++ type - Variant B 
    class MONObjectImp; 
    
    @interface MONObject : NSObject 
    { 
    @private 
    MON::t_auto_pointer<MONObjectImp> imp; 
    } 
    @end 
    

    注:これは、もともと書かれていたので、@implementationブロックでアイバーズを宣言する機能が導入されているあなたは、あなたを宣言する必要があります。古いツールチェーンや「壊れやすい」32ビットOS X ABIをサポートする必要がない場合は、C++にタイプします。

    C++バリアントAは他のクラスと同じように安全ではありません。クラスAの宣言がクライアントに表示される必要があるためです。それ以外の場合は、インプリメンテーションファイル内のImpクラスを宣言し、定義することができます(クライアントから隠す)。

    次に、選択したインターフェイスを公開することができます。もちろん、クライアントは実行時に実際にアクセスしたい場合でもメンバーにアクセスできます。これはObjC Impタイプで安全に行うのが最も簡単です。つまり、objcランタイムはメンバーのC++セマンティクスをサポートしていないため、クライアントはUBを要求しています(IOWはすべて実行時のPODです)。

    ObjC実装のランタイム・コストは、新しいタイプを作成し、インスタンスごとに新しいImpインスタンスを作成し、メッセージングを2倍にすることです。

    割当(バリアントB)を除いて、C++タイプは実質的に何も費用がかかりません。

    オプションE

    他のアプローチは、多くの場合、界面からアイバーズを解離します。 これは良いことです、それはObjCのタイプでも非常に珍しいことです。 ObjCの型/デザインは、しばしばイールカーやアクセサに密接に関連しているので、他の開発者からの抵抗に直面するでしょう。

  • 関連する問題