2009-04-27 6 views
30

私がC#で本当に好きなのは、一般的なリストです。 1つのタイプのオブジェクトのみを含むリスト。 Cocoa/Objective-Cに汎用リストのようなものがありますか?今まで私はNSArrayを知っています。誰がどのオブジェクトにポインタをとるのでしょうか。Cocoa/Objective-Cに汎用リストのようなものはありますか?

+0

Objective-Cは、タイプリレーションシップではなく、プロトコル(インターフェイス)準拠のシステムです。 IMO、あなたが実際に尋ねることは、コレクションのすべての要素が特定のプロトコル(インタフェース)に準拠するように、コンパイラがコレクション型をインスタンス化するための方法があるかどうかです。 –

答えて

34

これはココアアプリでは、しばしば弱いデザインの兆候です。

NSArrayは不変なので、オブジェクトにポインタを渡すことはなく、おそらくあなたに渡されたときに正しいオブジェクトが既に含まれていると考えられます。私があなたが心配しているのはNSMutableArrayです。あなたのコードの他の部分が間違った種類のオブジェクトを追加するかもしれないと思います。しかし、ココア自体を見てみましょう。クラスのデザインの一部として可変配列を公開することは非常にまれです。

代わりにNSArrayと、その配列を変更するための2つの方法が公開されています。線に沿って何か:

@class Foo : NSObject 
- (NSArray *)bars; 
- (void)addBar:(Bar *)bar; 
- (void)removeBar:(Bar *)bar; 
@end 

これは、一般的に、単にコンパイラの警告を持つことによって挿入される間違ったオブジェクトを停止し、あなたも望むならば、もちろんあなたは-addBar:-removeBar:内アサーションを追加することができます。

+0

素晴らしい答え。どうもありがとう。私が心に持っていたもの。 – TalkingCode

+0

また、より高度な操作が必要な場合は、-mutableArrayValueForKeyを読んでください: –

+0

+1「弱いデザインがしばしばあります」 –

9

Objective-Cは汎用プログラミングをサポートしていません。 Objective-C++とSTLリストはいつでも使用できます。

3

汎用NSArrayは、NSArrayをサブクラス化し、提供されたすべてのメソッドをより限定的に再定義することで実現できます。例えば、

- (id)objectAtIndex:(NSUInteger)index 

はNSStringsを含むようにNSArrayのため

- (NSString *)objectAtIndex:(NSUInteger)index 

として

@interface NSStringArray : NSArray 

で再定義しなければならないであろう。

作成されたサブクラスをドロップイン置換として使用すると、コンパイラの警告、プロパティへのアクセス、より良いコードの作成、およびXcodeでの完全な機能など、多くの便利な機能が実現します。これらはすべてコンパイル時の機能であり、実際の実装を再定義する必要はありません.NSArrayのメソッドは引き続き使用できます。

これを自動化して2つのステートメントだけにすることができます。これにより、ジェネリックをサポートする言語に近づけることができます。私はWMGenericCollectionのオートメーションを作成しました。テンプレートはCプリプロセッサマクロとして提供されています。

マクロを含むヘッダーファイルをインポートした後、インターフェイス用と実装用の2つのステートメントで汎用NSArrayを作成できます。格納するデータ型とサブクラスの名前を指定するだけで済みます。 WMGenericCollectionは、NSArray,NSDictionaryおよびNSSetのテンプレートを提供します。また、対応する対応するテンプレートも用意されています。

+0

あなたの答えを投稿してくれてありがとう! [自己プロモーションに関するよくある質問](http://stackoverflow.com/faq#promotion)をよく読んでください。また、自分のサイト/製品にリンクするたびに免責条項を掲示することが必須*であることにも注意してください。 –

+0

それを指摘してくれてありがとう。私はこれをどうやって行うのか、あるいはそれがスパムすぎると考えられるかどうか不明であった。今私は忙しいですが、私は2時間以内にガイドラインに従って回答を取り直します。 –

+0

優秀!あなたの最後の2つの答えは、問題に対処しているように思われるので、あなたはいくつかの良い情報を含んでいます(「このプロジェクトをここに見る」と機能リストは含まれていません)。ちょうど開示を追加して、彼らはちょうどいいです。再度、感謝します!ああ、また。ちょうどFYI;正確な回答のコピーを投稿することに注意してください。これらは質問には十分だと思われますが、質問に対する回答を具体的に調整しようとしてください。 –

0

いいえ、Objective-Cは現在、コレクション要素のパラメトリックタイピングをサポートしていません。

しかし、このトピックは質問または既存の回答よりも複雑です。

Objective-Cのコレクションのパラメトリック型は、C#/ JavaのGenericsと同じではありません。たとえば、Objective-Cがコレクションに追加されたすべてのオブジェクトを保証する機能を追加することはありません。IS NSArrayタイプまたはサブタイプ。代わりに、Objective-Cはコレクション内のすべてのオブジェクトを保証する能力を持つことができます(そしてIMOは)準拠プロトコル/インターフェイスへのです。 (つまり、一連の必要な方法を実装している)

なぜですか?

Objective-Cは、プロトコル(インタフェース)の互換性に基づいて構築された言語であり、リレーションシップをサブタイプ化するものではありません。つまり、オブジェクトが適切なメソッドを持っていれば、オブジェクトは互換性があり、実際の型を見たり気にしたりしません。実際、実際の型を見ることは、Obj-Cでは非常に悪い習慣であり、非常に落胆しています。この考え方は、「アヒルタイピング」と呼ばれることもあります。なぜなら、アヒルのように突き刺すと、それはアヒルだからです。特定のアヒルから文字通り継承されているかどうかは気にしません。これにより、elsesの実装階層に抱かれてしまうのを防ぎます。その結果、リストから出てくるオブジェクトにdraw ::メソッドがある限り、特定のJimmyDrawableBaseオブジェクトのサブクラスであるかどうかは実際には気にしません。

これは、コードをより再利用できるだけでなく、与えられた基本クラスから派生しているオブジェクトに頼ることができないため、多少異なる(より機能的な)タイプの問題分解を促します。あなたの基本クラスの実装はそれらに強制されました。

私は個人的に*それはPROTOCOL *適合パラメトリックチェックを持っているのObj-Cコンパイラの素敵だろうと思います。つまり、その中に置かれたすべてのオブジェクトが所定のプロトコルに準拠していることを要求するNSMutableArrayを作成します(つまり、必要なメソッドのセットを持っている)。

時には、この柔軟性の高いプロトコル準拠チェックでさえ、ダイナミックなプログラミングの人々や、健全な理由によって抵抗されます。プログラマーは、しばしば、適合要件を過度に指定する方法を持っています。

たとえば、リストにNSArrayプロトコル/インターフェイスに準拠したオブジェクトが含まれていることが必要な場合がありますが、ACTUALLYはこれらのメソッドのうちの2つだけを呼び出します。これは過適合です。あなたの配列に互換性のあるアイテムを張りたいと思っている人は、あなたが実際に呼び出すことのないたくさんのメソッドを実装する必要があります。

Google Goでは、構造的な互換性を推測することでこの問題を解決しようとしています。つまり、リストから出てくる項目に対してdraw()を呼び出すと、コンパイラはリストに入るすべてがdraw()メソッドを含むことを保証します。 draw()メソッドが含まれていない場合、それをリストに入れるのはコンパイラエラーです。これにより、コードで実行時に同じエラーが発生するのを単純に防止できます。この問題は、プログラム全体のコンパイルでしか機能しないという問題があります。 Google-GoがモジュラーDLLをコンパイルできれば、リスト内のオブジェクトが3つのメソッドの特定のインタフェースをサポートする必要があると言うことができないという問題が発生します。私はが将来彼らに電話するかもしれないので、今日電話していません

この2つのソリューションの間には、トレードオフと真実があります。

個人的に、私はObjective-Cのパラメトリックプロトコル準拠の追加を参照してくださいしたいと思いますので、私はいつものプロトコルの特定のセットに準拠して、特定のコレクションの内容を保証するために、コンパイラを求めることができます。

私はまた、過適合を避けるためにコンパイラを使用したいと思います。私がオブジェクト上のそれらのプロトコルでメソッドを呼び出すのでなければ、エラー/警告が生成されるはずです。私がそれらを使用していなくてもプロトコルでそれらを保持したいなら、私は明示的にそれが "将来使用されるかもしれないプロトコルの各メソッドの宣言をしなければならないので、要素は今それをすべて供給する必要があります"これは少なくとも、Java/C#ではなく、より少ない作業で多くの作業が必要になります。

+0

"実際、実際の型を見ることは、Obj-Cでは非常に悪い習慣であり、非常に落胆しています。それを拡大できますか?すべての標準データオブジェクトは、プロトコルではなく継承で実装されます。例NSDecimalNumberを取る:NSNumber:NSValue:NSObject。または、プロトコルを提供しないNSString。したがって、2つのコンパイル時のオプションのうち、isKindOfClass:はconformsToProtocol:canできない間に使用できます。その悪い習慣はどうですか? –

関連する問題