id
与void *
有什么区别?Objective-C:id与void的区别*
回答
void *
装置
id
手段‘未知类的一些随机Objective-C的对象的引用’,“一些随机块O”与无类型/未知内容存储器中的参考”
有附加的语义差异:
在GC Only或GC支持的模式,编译器将发出对
id
类型的引用写的障碍,而不是类型。在声明结构时,这可能是一个关键的区别。如果_superPrivateDoNotTouch
实际上是一个对象,声明像void *_superPrivateDoNotTouch;
这样的iVars将导致对象过早收割。不要这样做。试图调用一个引用
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()有条件地按照区分大小写或不区分大小写的方式进行排序,而且仍然是线程安全的,则可以在上下文中传递区分大小写的指示符,可能会在进出的方式中进行投射。
脆弱和容易出错,但唯一的办法。
块解决这个问题 - 块是C的关闭。它们可以在Clang - http://llvm.org/中找到,并且在Snow Leopard中很普遍(http://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/GCD_libdispatch_Ref.pdf)。
如果方法的返回类型为id
,那么您可以返回任何Objective-C对象。
void
表示该方法不会返回任何东西。
void *
只是一个指针。您将无法编辑指针指向的地址上的内容。
由于它适用于方法的返回值,大部分都是正确的。因为它适用于声明变量或参数,不完全。如果你想读/写内容,你总是可以将一个(void *)类型转换为更具体的类型 - 而不是这样做是一个好主意。 – bbum 2009-08-20 06:31:02
我的理解是,ID都代表一个指向对象的指针,而无效*可以指向任何真的,只要你然后将它转换为你想用它作为
如果您从(void *)转换为某种对象类型(包括id),那么很可能是错误的。有理由这样做,但它们很少,几乎总是表明设计缺陷。 – bbum 2009-08-20 06:27:01
引用“有理由这样做,但他们很少,远在”真的。这取决于实际情况。然而,我不会在一些背景下做出像“你很可能做错了”这样的总括性陈述。 – hhafez 2009-08-20 06:36:34
我会做一个总括性的陈述;不得不寻找并修复太多该死的错误,因为它们之间有void *类型的错误类型。一个例外是基于回调的API,其采用void *上下文参数,其合约声明上下文在设置回调和接收回调之间保持不变。 – bbum 2009-08-20 06:54:03
ID类型是一个指向客观的C对象,其中void *是一个指向任何东西的指针。
ID也关闭相关的调用未知mthods警告,因此,例如:
[(id)obj doSomethingWeirdYouveNeverHeardOf];
不会放弃对未知的方法通常的警告。当然,它会在运行时引发异常,除非obj不存在或者确实实现了该方法。
通常你应该优先使用NSObject*
或id<NSObject>
到id
,至少证实了返回的对象是一个Cocoa对象,所以你可以放心地使用像保留它/发行/自动释放的方法。
对于方法调用,如果目标方法尚未在任何地方声明,则类型(id)的目标将生成警告。因此,在你的例子中,doSomethingWeirdYouveNeverHeardOf将不得不被宣布某处,因为没有警告。 – bbum 2009-08-20 06:26:05
你是对的,一个更好的例子就像storagePolicy。 – 2009-08-21 01:03:57
@PeterNLewis我不同意'通常你应该使用NSObject *'而不是'id'。通过指定“NSObject *”,你实际上明确表示该对象是一个NSObject。任何方法调用对象都会导致警告,但只要该对象确实响应方法调用,就不会产生运行时异常。警告显然很烦人,所以'id'更好。粗糙的你可以通过例如'id
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 *)类型变量根本不可能成为方法调用的目标。它会导致编译器“警告:无效的接收器类型'void *'”。 – bbum 2009-08-20 06:24:43
@bbum:'void *'类型变量绝对可以作为方法调用的目标 - 这是一个警告,而不是一个错误。不仅如此,你可以这样做:'int i =(int)@“Hello,string!”;'并且跟随:'printf(“发送到int:'%s'\ n”,[UTF8String ]);'。这是一个警告,而不是一个错误(不完全建议,也不便携)。但是你能做这些事情的原因都是基本的C. – johne 2009-08-22 22:17:16
对不起。你是对的;这是一个警告,而不是一个错误。我只是将警告视为总是随处可见的错误。 – bbum 2009-08-23 01:48:58
/// 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类对象绑定,而无效*仅仅是一个无类型指针。
除了已经说过的内容之外,与集合相关的对象和指针还有区别。例如,如果您想将某些东西放入NSArray中,您需要一个对象(类型为“id”),并且不能在那里使用原始数据指针(类型为“void *”)。您可以使用[NSValue valueWithPointer:rawData]
将void *rawDdata
转换为“id”类型以在集合中使用它。一般而言,“id”更灵活,并且与附加到它的对象相关的语义更多。有更多的例子解释id type of Objective C here。
- 1. void __iomem *和void * __iomem之间的区别?
- 2. void(* xmlHashScanner)和void * xmlHashScanner之间的区别
- 3. “void function()”和“void * function()”有什么区别?
- 4. void *和void **有什么区别?
- 5. (void **)&x和(void *)x有什么区别?
- 6. void(int)和void(*)(int)有什么区别?
- 7. 从“typedef void VOID”中内置“void”和“VOID”有什么区别?
- 8. char函数(void)和void函数(void)之间的C区别
- 9. void *和char *之间的区别*
- 10. void main和int之间的区别主
- 11. EventHandler和delegete之间的区别void()
- 12. virtual void funcFoo()const = 0和virtual void funcFoo()= 0之间的区别;
- 13. “virtual void IBase :: Foo”和“virtual void Foo”之间的区别是什么?
- 14. “public void onDestroy()”和“protected void onDestroy()”之间的区别?
- 15. c#中static void main(string [] args)和static void main()之间的区别?
- 16. C中的void和static void函数有什么区别?
- 17. 静态内联void和void之间有什么区别?
- 18. new Thread(void Target())和new Thread(new ThreadStart(void Target()))有什么区别?
- 19. 在C++中,VOID和void是否有区别?
- 20. EventEmitter <undefined>与EventEmitter <void>有什么区别?
- 21. 点与!的区别
- 22. “或”与“||”的区别
- 23. public final void moveCamera(CameraUpdate update)和public final void animateCamera(CameraUpdate update)之间的区别?
- 24. public static void main(String [] args)和public static void main(String args [])之间的区别?
- 25. <T extends A> void foo(T t)和void foo(A a)之间的区别
- 26. 函数定义中的指针与数组:void fct1(int * p)和void fct1(int p [])有什么区别?
- 27. C中的main(void)和main()之间的区别
- 28. 请告诉我无效*和void *的之间的区别
- 29. 声明一个线程函数是否返回void和void *有区别吗?
- 30. DocBook与HTML - 区别
另外,我非常确定'id'被认为是对'-retain'和'-release'做出响应,而'void *'对被调用者是完全不透明的。您不能将任意指针传递给'-performSelector:withObject:afterDelay:'(它保留了该对象),并且您不能假设'+ [UIView beginAnimations:context:]'将保留上下文(动画委托应该保持上下文的所有权; UIKit保留动画委托)。 – 2010-10-13 20:02:12
对'id'响应的内容不做任何假设。一个'id'可以很容易地引用一个不是'NSObject'固有的类的实例。但实际上,你的陈述最符合现实世界的行为;你不能混合使用Foundation API的非''实现类,并且得到很远,这绝对是肯定的! –
bbum
2010-10-13 22:42:37
现在'id'和'Class'类型被视为ARC下的[*可保留对象指针*](http://clang.llvm.org/docs/AutomaticReferenceCounting.html#objects)。所以这个假设至少在ARC下是真实的。 – Eonil 2012-12-05 11:14:15