2009-08-20 92 views

回答

231

void *装置

id手段‘未知类的一些随机Objective-C的对象的引用’,“一些随机块O”与无类型/未知内容存储器中的参考”

有附加的语义差异:

  • 在GC Only或GC支持的模式,编译器将发出对id类型的引用写的障碍,而不是类型。在声明结构时,这可能是一个关键的区别。如果_superPrivateDoNotTouch实际上是一个对象,声明像void *_superPrivateDoNotTouch;这样的iVars将导致对象过早收割。不要这样做。

  • 试图调用一个引用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()有条件地按照区分大小写或不区分大小写的方式进行排序,而且仍然是线程安全的,则可以在上下文中传递区分大小写的指示符,可能会在进出的方式中进行投射。

脆弱和容易出错,但唯一的办法。

块解决这个问题 - 块是C的关闭。它们可以在Clang - http://llvm.org/中找到,并且在Snow Leopard中很普遍(http://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/GCD_libdispatch_Ref.pdf)。

+0

另外,我非常确定'id'被认为是对'-retain'和'-release'做出响应,而'void *'对被调用者是完全不透明的。您不能将任意指针传递给'-performSelector:withObject:afterDelay:'(它保留了该对象),并且您不能假设'+ [UIView beginAnimations:context:]'将保留上下文(动画委托应该保持上下文的所有权; UIKit保留动画委托)。 – 2010-10-13 20:02:12

+3

对'id'响应的内容不做任何假设。一个'id'可以很容易地引用一个不是'NSObject'固有的类的实例。但实际上,你的陈述最符合现实世界的行为;你不能混合使用Foundation API的非''实现类,并且得到很远,这绝对是肯定的! – bbum 2010-10-13 22:42:37

+2

现在'id'和'Class'类型被视为ARC下的[*可保留对象指针*](http://clang.llvm.org/docs/AutomaticReferenceCounting.html#objects)。所以这个假设至少在ARC下是真实的。 – Eonil 2012-12-05 11:14:15

8

如果方法的返回类型为id,那么您可以返回任何Objective-C对象。

void表示该方法不会返回任何东西。

void *只是一个指针。您将无法编辑指针指向的地址上的内容。

+2

由于它适用于方法的返回值,大部分都是正确的。因为它适用于声明变量或参数,不完全。如果你想读/写内容,你总是可以将一个(void *)类型转换为更具体的类型 - 而不是这样做是一个好主意。 – bbum 2009-08-20 06:31:02

2

我的理解是,ID都代表一个指向对象的指针,而无效*可以指向任何真的,只要你然后将它转换为你想用它作为

+0

如果您从(void *)转换为某种对象类型(包括id),那么很可能是错误的。有理由这样做,但它们很少,几乎总是表明设计缺陷。 – bbum 2009-08-20 06:27:01

+1

引用“有理由这样做,但他们很少,远在”真的。这取决于实际情况。然而,我不会在一些背景下做出像“你很可能做错了”这样的总括性陈述。 – hhafez 2009-08-20 06:36:34

+0

我会做一个总括性的陈述;不得不寻找并修复太多该死的错误,因为它们之间有void *类型的错误类型。一个例外是基于回调的API,其采用void *上下文参数,其合约声明上下文在设置回调和接收回调之间保持不变。 – bbum 2009-08-20 06:54:03

19

ID类型是一个指向客观的C对象,其中void *是一个指向任何东西的指针。

ID也关闭相关的调用未知mthods警告,因此,例如:

[(id)obj doSomethingWeirdYouveNeverHeardOf];

不会放弃对未知的方法通常的警告。当然,它会在运行时引发异常,除非obj不存在或者确实实现了该方法。

通常你应该优先使用NSObject*id<NSObject>id,至少证实了返回的对象是一个Cocoa对象,所以你可以放心地使用像保留它/发行/自动释放的方法。

+2

对于方法调用,如果目标方法尚未在任何地方声明,则类型(id)的目标将生成警告。因此,在你的例子中,doSomethingWeirdYouveNeverHeardOf将不得不被宣布某处,因为没有警告。 – bbum 2009-08-20 06:26:05

+0

你是对的,一个更好的例子就像storagePolicy。 – 2009-08-21 01:03:57

+0

@PeterNLewis我不同意'通常你应该使用NSObject *'而不是'id'。通过指定“NSObject *”,你实际上明确表示该对象是一个NSObject。任何方法调用对象都会导致警告,但只要该对象确实响应方法调用,就不会产生运行时异常。警告显然很烦人,所以'id'更好。粗糙的你可以通过例如'id 来更具体化,在这种情况下,无论对象是什么,它都必须符合MKAnnotation协议。 – pnizzle 2017-05-04 07:09:29

7

id是一个指向Objective-C对象的指针。 void *是指向的任何东西。您可以使用void *而不是id,但不建议这样做,因为您不会收到任何编译器警告。

你可能想看到stackoverflow.com/questions/466777/whats-the-difference-between-declaring-a-variable-id-and-nsobjectunixjunkie.blogspot.com/2008/03/id-vs-nsobject-vs-id.html

+1

不完全。 (void *)类型变量根本不可能成为方法调用的目标。它会导致编译器“警告:无效的接收器类型'void *'”。 – bbum 2009-08-20 06:24:43

+0

@bbum:'void *'类型变量绝对可以作为方法调用的目标 - 这是一个警告,而不是一个错误。不仅如此,你可以这样做:'int i =(int)@“Hello,string!”;'并且跟随:'printf(“发送到int:'%s'\ n”,[UTF8String ]);'。这是一个警告,而不是一个错误(不完全建议,也不便携)。但是你能做这些事情的原因都是基本的C. – johne 2009-08-22 22:17:16

+0

对不起。你是对的;这是一个警告,而不是一个错误。我只是将警告视为总是随处可见的错误。 – bbum 2009-08-23 01:48:58

4
/// 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 struct和isa指针的实例可以与任何目标C类对象绑定,而无效*仅仅是一个无类型指针。

0

除了已经说过的内容之外,与集合相关的对象和指针还有区别。例如,如果您想将某些东西放入NSArray中,您需要一个对象(类型为“id”),并且不能在那里使用原始数据指针(类型为“void *”)。您可以使用[NSValue valueWithPointer:rawData]void *rawDdata转换为“id”类型以在集合中使用它。一般而言,“id”更灵活,并且与附加到它的对象相关的语义更多。有更多的例子解释id type of Objective C here

相关问题