Objective-C:id 和 void * 之间的区别 [英] Objective-C: difference between id and void *
问题描述
id
和 void *
有什么区别?
void *
的意思是对一些随机内存块的引用,其中包含无类型/未知内容"
id
表示对未知类的某个随机 Objective-C 对象的引用"
还有其他语义差异:
在 GC Only 或 GC Supported 模式下,编译器将为
id
类型的引用发出写屏障,但不会为void *
类型的引用发出写屏障.在声明结构时,这可能是一个关键差异.如果_superPrivateDoNotTouch
实际上是一个对象,则声明像void *_superPrivateDoNotTouch;
这样的 iVar 将导致过早地获取对象.不要那样做.尝试对
void *
类型的引用调用方法将导致编译器警告.尝试调用
id
类型的方法只会在被调用的方法未在任何@interface
声明中声明时发出警告编译器.
因此,永远不要将对象称为 void *
.同样,应该避免使用 id
类型变量来引用对象.尽可能使用最具体的类类型引用.甚至 NSObject *
也比 id
更好,因为编译器至少可以针对该引用提供更好的方法调用验证.
void *
的一个常见且有效的用途是作为通过其他 API 传递的不透明数据引用.
考虑NSArray
的sortedArrayUsingFunction:context:
方法:
- (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).
What is the difference between id
and void *
?
void *
means "a reference to some random chunk o' memory with untyped/unknown contents"
id
means "a reference to some random Objective-C object of unknown class"
There are additional semantic differences:
Under GC Only or GC Supported modes, the compiler will emit write barriers for references of type
id
, but not for typevoid *
. When declaring structures, this can be a critical difference. Declaring iVars likevoid *_superPrivateDoNotTouch;
will cause premature reaping of objects if_superPrivateDoNotTouch
is actually an object. Don't do that.attempting to invoke a method on a reference of
void *
type will barf up a compiler warning.attempting to invoke a method on an
id
type will only warn if the method being called has not been declared in any of the@interface
declarations seen by the compiler.
Thus, one should never refer to an object as a void *
. Similarly, one should avoid using an id
typed variable to refer to an object. Use the most specific class typed reference you can. Even NSObject *
is better than id
because the compiler can, at the least, provide better validation of method invocations against that reference.
The one common and valid use of void *
is as an opaque data reference that is passed through some other API.
Consider the sortedArrayUsingFunction: context:
method of NSArray
:
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context;
The sorting function would be declared as:
NSInteger mySortFunc(id left, id right, void *context) { ...; }
In this case, the NSArray merely passes whatever you pass in as the context
argument to the method through as the context
argument. It is an opaque hunk of pointer sized data, as far as NSArray is concerned, and you are free to use it for whatever purpose you want.
Without a closure type feature in the language, this is the only way to carry along a hunk of data with a function. Example; if you wanted mySortFunc() to conditionally sort as case sensitive or case insensitive, while also still being thread-safe, you would pass the is-case-sensitive indicator in the context, likely casting on the way in and way out.
Fragile and error prone, but the only way.
Blocks solve this -- Blocks are closures for C. They are available in Clang -- http://llvm.org/ and are pervasive in Snow Leopard (http://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/GCD_libdispatch_Ref.pdf).
这篇关于Objective-C:id 和 void * 之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!