web-dev-qa-db-ja.com

Objective-Cには強く型付けされたコレクションがありますか?

Mac/iPhoneプログラミングとObjective-Cは初めてです。 C#とJavaには、ジェネリック型、宣言された型のみをメンバーとするコレクションクラスがあります。たとえば、C#では

Dictionary<int, MyCustomObject>

タイプがMyCustomObjectの整数と値であるキーのみを含めることができます。 Objective-Cにも同様のメカニズムが存在しますか?

138
Rich

Xcode 7では、Appleは 'Lightweight Generics'をObjective-Cに導入しました。Objective-Cでは、型の不一致がある場合にコンパイラ警告を生成します。

NSArray<NSString*>* arr = @[@"str"];

NSString* string = [arr objectAtIndex:0];
NSNumber* number = [arr objectAtIndex:0]; // Warning: Incompatible pointer types initializing 'NSNumber *' with an expression of type 'NSString *'

そして、Swiftコードでは、コンパイラエラーが生成されます。

var str: String = arr[0]
var num: Int = arr[0] //Error 'String' is not convertible to 'Int'

Lightweight GenericsはNSArray、NSDictionary、NSSetで使用することを目的としていますが、独自のクラスに追加することもできます。

@interface GenericsTest<__covariant T> : NSObject

-(void)genericMethod:(T)object;

@end

@implementation GenericsTest

-(void)genericMethod:(id)object {}

@end

Objective-Cは、コンパイラの警告が表示される前と同じように動作します。

GenericsTest<NSString*>* test = [GenericsTest new];

[test genericMethod:@"string"];
[test genericMethod:@1]; // Warning: Incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *'

しかしSwiftは汎用情報を完全に無視します。(Swift 3+。

var test = GenericsTest<String>() //Error: Cannot specialize non-generic type 'GenericsTest'

これらのFoundationコレクションクラスを除き、Objective-C軽量ジェネリックはSwiftによって無視されます。軽量ジェネリックを使用するその他の型は、パラメータ化されていないかのようにSwiftにインポートされます。

Objective-C APIとの対話

209
Connor

この答えは時代遅れですが、歴史的な価値のために残っています。 Xcode 7の時点で、15年6月8日からのコナーの答えはより正確です。


いいえ、独自のカスタムコレクションクラスでC++テンプレートを使用する場合を除き、Objective-Cにはジェネリックはありません(強くお勧めしません)。

Objective-Cには動的タイピング機能があります。つまり、すべてのオブジェクトがメッセージを受信できるため、ランタイムはオブジェクトのタイプを気にしません。組み込みコレクションにオブジェクトを追加すると、それらはid型であるかのように扱われます。しかし、心配しないで、通常のようにそれらのオブジェクトにメッセージを送信するだけです。 (もちろん、コレクション内の1つ以上のオブジェクトが、送信しているメッセージに応答しない限り)です。

JavaやC#などの言語ではジェネリックが必要です。これらは強力で静的に型付けされた言語であるためです。Objective-Cの動的型付け機能とはまったく異なります。

91
Marc W

いいえ、しかし、より明確にするために、保存したいオブジェクトのタイプでコメントすることができます。Java 1.4最近)で何かを書く必要があるとき、これを数回見ました例えば:

NSMutableArray* /*<TypeA>*/ arrayName = ....

または

NSDictionary* /*<TypeA, TypeB>*/ dictionaryName = ...
11
Mark Rhodes

Objective-Cにはジェネリックはありません。

ドキュメントから

配列は、オブジェクトの順序付けられたコレクションです。 Cocoaは、NSArray、NSMutableArray(NSArrayのサブクラス)、およびNSPointerArrayのいくつかの配列クラスを提供します。

6
Matthew Vines

Appleは、XCode 7でObjCにジェネリックを追加しました。

@property NSArray<NSDate *>* dates;
- (NSArray<NSDate *> *)datesBeforeDate:(NSDate *)date;
- (void)addDatesParsedFromTimestamps:(NSArray<NSString *> *)timestamps;

こちらを参照してください: https://developer.Apple.com/library/prerelease/mac/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//Apple_ref/doc/uid/TP40014216-CH6-ID61 =

6
user1259710

これはXcode 7でリリースされました (最終的に!)

Objective Cコードでは、コンパイル時のチェックにすぎないことに注意してください。間違った型をコレクションに入れたり、型指定されたプロパティに割り当てたりするだけの実行時エラーはありません。

宣言:

@interface FooClass <T> : NSObject
@property (nonatomic) T prop;
@end

つかいます:

FooClass<NSString *> *foo = [[FooClass alloc] init];
NSArray<FooClass<NSString *> *> *fooAry = [NSArray array];

それらに注意してください*s。

5
Kevin

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

- (id)objectAtIndex:(NSUInteger)index

で再定義する必要があります

@interface NSStringArray : NSArray

なので

- (NSString *)objectAtIndex:(NSUInteger)index

nSStringのみを含むNSArrayの場合。

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

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

マクロを含むヘッダーファイルをインポートした後、2つのステートメントを持つ汎用NSArrayを作成できます。1つはインターフェイス用、もう1つは実装用です。保存するデータ型とサブクラスの名前を指定するだけです。 WMGenericCollectionは、NSArrayNSDictionary、およびNSSetのテンプレート、およびそれらの可変の対応するテンプレートを提供します。

例:List<int>は、次のステートメントで作成されるNumberArrayというカスタムクラスによって実現できます。

WMGENERICARRAY_INTERFACE(NSNumber *, // type of the value class
                         // generated class names
                         NumberArray, MutableNumberArray)

NumberArrayを作成したら、プロジェクトのあらゆる場所で使用できます。 <int>の構文はありませんが、独自の命名スキームを選択して、これらをクラスとしてテンプレートとしてラベル付けできます。

4
w-m

夢が実現しました。今日からObjective-Cにはジェネリック医薬品があります(ありがとう、WWDC)。それは冗談ではありません-Swiftの 公式ページ で:

新しい構文機能により、表現力豊かなコードを記述しながら、言語全体の一貫性を改善できます。 SDKは、ジェネリックやnullabilityアノテーションなどの新しいObjective-C機能を使用して、Swiftコードをよりクリーンで安全にしています。ここでは、Swift 2.0機能強化。

そしてこれを証明する画像:Objective-C generics

2
htzfun

を見てみましょう:

https://github.com/tomersh/Objective-C-Generics

プロトコルチェックメカニズムを再利用することにより、一種の貧乏人のジェネリックのように見えます。

2
David Jeske

ここに飛び込みたいだけです。私はブログ投稿を書きました こちら Genericsについて。

私が貢献したいことは、ジェネリックを任意のクラスに追加できることです。コレクションクラスだけでなく、Apple示します。

Appleのコレクションとまったく同じように機能するため、さまざまなクラスに追加しました。すなわち。コンパイル時のチェック、コード補完、キャストの削除の有効化など。

楽しい。

2
drekka