小编典典

Objective-C: id 和 void * 的区别

all

id和 和有什么不一样void *


阅读 522

收藏
2022-08-29

共1个答案

小编典典

void *表示“对具有无类型/未知内容的一些随机内存块的引用”

id表示“对未知类的一些随机 Objective-C 对象的引用”

还有其他语义差异:

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

  • 尝试在void *类型的引用上调用方法会引发编译器警告。

  • 尝试调用id类型上的方法只会在被调用的方法没有在@interface编译器看到的任何声明中声明时发出警告。

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

一个常见且有效的用途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()
有条件地排序为区分大小写或不区分大小写,同时仍然是线程安全的,您将在上下文中传递区分大小写的指示符,可能会在进出时进行强制转换。

脆弱且容易出错,但这是唯一的方法。

块解决了这个问题——块是 C 的闭包。它们在 Clang 中可用——http:
//llvm.org/并且在雪豹中普遍存在(http://developer.apple.com/library/ios/documentation/Performance
/参考/GCD_libdispatch_Ref/GCD_libdispatch_Ref.pdf)。

2022-08-29