Objective-C:id 和 void * 之间的区别 [英] Objective-C: difference between id and void *

查看:44
本文介绍了Objective-C:id 和 void * 之间的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

idvoid * 有什么区别?

解决方案

void * 的意思是对一些随机内存块的引用,其中包含无类型/未知内容"

id 表示对未知类的某个随机 Objective-C 对象的引用"

还有其他语义差异:

  • 在 GC Only 或 GC Supported 模式下,编译器将为 id 类型的引用发出写屏障,但不会为 void * 类型的引用发出写屏障.在声明结构时,这可能是一个关键差异.如果 _superPrivateDoNotTouch 实际上是一个对象,则声明像 void *_superPrivateDoNotTouch; 这样的 iVar 将导致过早地获取对象.不要那样做.

  • 尝试对 void * 类型的引用调用方法将导致编译器警告.

  • 尝试调用 id 类型的方法只会在被调用的方法未在任何 @interface 声明中声明时发出警告编译器.

因此,永远不要将对象称为 void *.同样,应该避免使用 id 类型变量来引用对象.尽可能使用最具体的类类型引用.甚至 NSObject * 也比 id 更好,因为编译器至少可以针对该引用提供更好的方法调用验证.

void * 的一个常见且有效的用途是作为通过其他 API 传递的不透明数据引用.

考虑NSArraysortedArrayUsingFunction: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 type void *. When declaring structures, this can be a critical difference. Declaring iVars like void *_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆