回答:
void *
「型なし/不明な内容のランダムなチャンクのメモリへの参照」を意味します
id
「不明なクラスのランダムなObjective-Cオブジェクトへの参照」を意味します
追加の意味上の違いがあります:
GC OnlyまたはGC Supportedモードでは、コンパイラーはtypeの参照に対しては書き込みバリアを発行しますが、typeに対しては発行しid
ませんvoid *
。構造体を宣言する場合、これは重大な違いになる可能性があります。のようvoid *_superPrivateDoNotTouch;
にiVarを宣言する_superPrivateDoNotTouch
と、実際にオブジェクトである場合に、オブジェクトの早すぎる刈り取りが発生します。しないでください。
void *
タイプの参照でメソッドを呼び出そうとすると、コンパイラ警告が表示されます。
id
型に対してメソッドを呼び出そうとすると、呼び出されているメソッドが@interface
コンパイラから見たどの宣言でも宣言されていない場合にのみ警告が表示されます。
したがって、オブジェクトをとして参照することはできませんvoid *
。同様に、id
型付き変数を使用してオブジェクトを参照することは避けてください。できる限り具体的なクラス型付き参照を使用します。NSObject *
より良好でありid
、コンパイラは、少なくとも、その基準に対するメソッド呼び出しのより良好な検証を提供することができるからです。
の一般的で有効な用途の1つvoid *
は、他のAPIを介して渡される不透明なデータ参照としてです。
次のsortedArrayUsingFunction: context:
方法を検討してくださいNSArray
。
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context;
ソート関数は次のように宣言されます。
NSInteger mySortFunc(id left, id right, void *context) { ...; }
この場合、NSArrayは、context
引数として渡されたものを引数としてメソッドに渡すだけですcontext
。NSArrayに関する限り、これはポインターサイズのデータの不透明な塊であり、必要に応じて自由に使用できます。
言語にクロージャー型の機能がない場合、これは関数でデータの塊を運ぶ唯一の方法です。例; mySortFunc()で条件付きで大文字と小文字を区別する、または区別しないで並べ替えたいが、スレッドセーフでもある場合は、コンテキストでis-case-sensitiveインジケーターを渡します。
壊れやすく、エラーが発生しやすいが、唯一の方法。
ブロックはこれを解決します-ブロックはCのクロージャーです。ブロックはClang- http://llvm.org/で利用可能で、Snow Leopard(http://developer.apple.com/library/ios/documentation/Performanceで広く使用されています) /Reference/GCD_libdispatch_Ref/GCD_libdispatch_Ref.pdf)。
id
応答するかについての想定はできません。id
簡単から本来のないクラスのインスタンスを参照することができますNSObject
。ただし、実際には、あなたの発言は実際の行動と最もよく一致します。非<NSObject>
実装クラスをFoundation APIと混在させて遠くに行くことはできません。
idは、目的のCオブジェクトへのポインターです。ここで、void *は、何かへのポインターです。
idは、不明なmthodsの呼び出しに関連する警告もオフにします。たとえば、次のようにします。
[(id)obj doSomethingWeirdYouveNeverHeardOf];
未知のメソッドに関する通常の警告は表示されません。もちろん、objがnilでないか、本当にそのメソッドを実装していない限り、実行時に例外が発生します。
多くの場合、を使用するNSObject*
かid<NSObject>
、を優先してid
、少なくとも返されたオブジェクトがCocoaオブジェクトであることを確認する必要があるため、retain / release / autoreleaseなどのメソッドを安全に使用できます。
Often you should use NSObject*
代わりに同意しませんid
。指定するNSObject*
ことで、実際にはオブジェクトがNSObjectであると明示的に言っています。オブジェクトへのメソッド呼び出しは警告になりますが、そのオブジェクトが実際にメソッド呼び出しに応答する限り、実行時例外は発生しません。警告は明らかに迷惑なのでid
、より良いです。次に、たとえばと言ってid<MKAnnotation>
、より具体的にすることができます。この場合、オブジェクトは何でも、MKAnnotationプロトコルに準拠している必要があります。
id
Objective-Cオブジェクトへのポインタです。void *
ポインタであるもの。のvoid *
代わりにを使用することもできますがid
、コンパイラの警告が表示されないため、これはお勧めできません。
あなたは見てみたいことがありstackoverflow.com/questions/466777/whats-the-difference-between-declaring-a-variable-id-and-nsobjectとunixjunkie.blogspot.com/2008/03/id-vs-nsobject-vs -id.html。
void *
型付き変数は、間違いなくメソッド呼び出しのターゲットになる可能性があります。これはエラーではなく警告です。:だけでなく、あなたがこれを行うことができ、それint i = (int)@"Hello, string!";
とフォローアップ:printf("Sending to an int: '%s'\n", [i UTF8String]);
。これは警告であり、エラーではありません(正確には推奨されておらず、移植性もありません)。しかし、あなたはこれらの事を行うことができる理由は、すべての基本的なC.ある
/// Represents an instance of a class.
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
上記のコードはobjc.hからのものであるため、idはobjc_object構造体のインスタンスであり、isaポインターは任意のObjective C Classオブジェクトにバインドできますが、void *は単なる型指定されていないポインターです。
私の理解では、idはオブジェクトへのポインタを表しますが、使用したい型にキャストする限り、void *は実際には何かを指すことができます。
既に述べたことに加えて、コレクションに関連するオブジェクトとポインタには違いがあります。たとえば、NSArrayに何かを入れたい場合、(「id」型の)オブジェクトが必要であり、そこに(「void *」型の)生データポインタを使用することはできません。コレクション内で使用[NSValue valueWithPointer:rawData]
するためvoid *rawDdata
に、「id」タイプに変換するために使用できます。一般に、「id」はより柔軟であり、それに接続されているオブジェクトに関連するセマンティクスが多くなります。Objective Cのidタイプを説明する他の例がここにあります。
id
に応答するもの-retain
と想定されていますが-release
、avoid*
は呼び出し先に対して完全に不透明です。任意のポインターを-performSelector:withObject:afterDelay:
(オブジェクトを保持する)に渡すことはできません。また、それが+[UIView beginAnimations:context:]
コンテキストを保持することは想定できません(アニメーションデリゲートはコンテキストの所有権を維持する必要があります。UIKitはアニメーションデリゲートを保持します)。