Mac/iPhone プログラミングと Objective-C は初めてです。C# と Java には、「ジェネリック」と呼ばれるコレクション クラスがあり、そのメンバーは宣言された型のみを持つことができます。たとえば、C# では
Dictionary<int, MyCustomObject>
整数のキーと MyCustomObject 型の値のみを含めることができます。同様のメカニズムが Objective-C に存在しますか?
Mac/iPhone プログラミングと Objective-C は初めてです。C# と Java には、「ジェネリック」と呼ばれるコレクション クラスがあり、そのメンバーは宣言された型のみを持つことができます。たとえば、C# では
Dictionary<int, MyCustomObject>
整数のキーと MyCustomObject 型の値のみを含めることができます。同様のメカニズムが Objective-C に存在しますか?
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'
軽量ジェネリックは、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 は Generic 情報を完全に無視します。(Swift 3 以降では当てはまりません。)
var test = GenericsTest<String>() //Error: Cannot specialize non-generic type 'GenericsTest'
これらの Foundation コレクション クラスを除いて、Objective-C の軽量ジェネリックは Swift によって無視されます。軽量ジェネリックを使用するその他の型は、パラメータ化されていないかのように Swift にインポートされます。
いいえ、しかし、より明確にするために、保存したいオブジェクトのタイプでコメントすることができます.最近Java 1.4で何かを書く必要があるときに、これが数回行われるのを見てきました)例:
NSMutableArray* /*<TypeA>*/ arrayName = ....
また
NSDictionary* /*<TypeA, TypeB>*/ dictionaryName = ...
Objective-C にはジェネリックはありません。
配列は、オブジェクトの順序付きコレクションです。Cocoa は、いくつかの配列クラス、NSArray、NSMutableArray (NSArray のサブクラス)、および NSPointerArray を提供します。
ジェネリック NSArray は、 をサブクラス化しNSArray
、提供されたすべてのメソッドをより制限的なメソッドで再定義することによって実現できます。例えば、
- (id)objectAtIndex:(NSUInteger)index
で再定義する必要があります
@interface NSStringArray : NSArray
なので
- (NSString *)objectAtIndex:(NSUInteger)index
NSArray が NSString のみを含むようにします。
作成されたサブクラスはドロップイン置換として使用でき、多くの便利な機能をもたらします: コンパイラ警告、プロパティ アクセス、より良いコード作成、および Xcode での補完。これらはすべてコンパイル時の機能であり、実際の実装を再定義する必要はありません。NSArray のメソッドは引き続き使用できます。
これを自動化して、たった 2 つのステートメントにまとめることができます。これにより、ジェネリックをサポートする言語に近づけることができます。テンプレートが C プリプロセッサ マクロとして提供されるWMGenericCollectionで自動化を作成しました。
マクロを含むヘッダー ファイルをインポートした後、インターフェイス用と実装用の 2 つのステートメントを含む汎用 NSArray を作成できます。保存するデータ型とサブクラスの名前を指定するだけです。WMGenericCollection はNSArray
、 、 、NSDictionary
およびNSSet
のようなテンプレートと、それに対応する変更可能なテンプレートを提供します。
例:は、次のステートメントで作成さList<int>
れる というカスタム クラスによって実現できます。NumberArray
WMGENERICARRAY_INTERFACE(NSNumber *, // type of the value class
// generated class names
NumberArray, MutableNumberArray)
を作成NumberArray
したら、プロジェクトのどこでも使用できます。の構文は<int>
ありませんが、独自の命名スキームを選択して、これらをクラスとしてテンプレートとしてラベル付けできます。
ここに飛び込みたいだけです。ジェネリックについては、こちらのブログ記事を書きました。
私が貢献したいのは、Apple が示すようにコレクション クラスだけでなく、ジェネリックを任意のクラスに追加できることです。
Appleのコレクションとまったく同じように機能するため、さまざまなクラスに正常に追加できました。すなわち。コンパイル時のチェック、コード補完、キャストの削除の有効化など。
楽しみ。
Apple および GNUStep フレームワークによって提供される Collections クラスは、ソート可能なオブジェクトと特定のメッセージに応答するオブジェクトが与えられていることを前提としているという点で、セミジェネリックです。float、int などのプリミティブの場合、すべての C 配列構造はそのままで使用できます。また、一般的なコレクション クラス (NSNumber など) で使用するための特別なラッパー オブジェクトがあります。さらに、Collection クラスは、任意の型のオブジェクトを受け入れるようにサブクラス化 (またはカテゴリを介して具体的に変更) することができますが、すべての型処理コードを自分で作成する必要があります。メッセージは任意のオブジェクトに送信できますが、オブジェクトに不適切な場合は null を返す必要があります。または、メッセージを適切なオブジェクトに転送する必要があります。真の型のエラーは、実行時ではなくコンパイル時にキャッチする必要があります。実行時には、それらを処理するか無視する必要があります。最後に、Objc は実行時のリフレクション機能を提供して、トリッキーなケースやメッセージ応答、特定の型、およびサービスを処理して、メッセージが送信されたり、不適切なコレクションに入れられたりする前にオブジェクトをチェックできます。異種のライブラリとフレームワークは、コード応答がないメッセージが送信されたときにオブジェクトがどのように動作するかについて、異なる規則を採用していることに注意してください。したがって、RTFM. おもちゃのプログラムとデバッグ ビルドを除いて、ほとんどのプログラムはクラッシュする必要はありません。ただし、実際に失敗してメモリやディスクに不正なデータを書き込もうとしたり、不正な操作を実行したり (たとえば、0 で除算しますが、それもキャッチできます)、アクセスしたりしない限り、クラッシュする必要はありません。システム リソースの制限を解除します。Objective-C のダイナミズムとランタイムにより、正常に失敗することが可能になり、コードに組み込む必要があります。(ヒント) 関数の汎用性に問題がある場合は、いくつかの特異性を試してください。関数を特定の型で上書きし、ランタイムが実行時に適切なメンバー関数を選択できるようにします (これがセレクターと呼ばれる理由です!)。
Example:
-(id) sort (id) obj; // too generic. catches all.
// better
-(id) sort: (EasilySortableCollection*) esc;
-(id) sort: (HardToSortCollection*) hsc;
...
[Sorter sort: MyEasyColl];
[Sorter sort: MyHardColl];