Answers:
void *
意思是“对带有未类型化/未知内容的随机块内存的引用”
id
表示“对未知类的某些随机Objective-C对象的引用”
还有其他语义差异:
在“仅GC”或“ GC支持”模式下,编译器将为type的引用id
而不是type的引用发出写屏障void *
。在声明结构时,这可能是关键的区别。void *_superPrivateDoNotTouch;
如果_superPrivateDoNotTouch
实际上将iVars声明为对象,则将导致对象的过早收割。不要那样做
尝试在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()有条件区分大小写或不区分大小写,同时仍然是线程安全的,则可以在上下文中传递is-区分大小写的指示符,可能会在进出时强制转换。
易碎且容易出错,但这是唯一的方法。
块解决了这一问题-块是C的闭包。它们在Clang中可用-http: //llvm.org/,在Snow Leopard中无处不在(http://developer.apple.com/library/ios/documentation/Performance /Reference/GCD_libdispatch_Ref/GCD_libdispatch_Ref.pdf)。
id
响应的假设。一个id
可以很容易地引用一个类是不从固有的一个实例NSObject
。但是,实际上,您的陈述最符合现实世界的行为。您不能将非<NSObject>
实现类与Foundation API 混合使用,并且走得很远,这是肯定的!
id是指向目标C对象的指针,其中void *是指向任何对象的指针。
id还关闭与调用未知方法有关的警告,例如:
[(id)obj doSomethingWeirdYouveNeverHeardOf];
不会对未知方法发出通常的警告。当然,除非obj为nil或确实实现了该方法,否则它将在运行时引发异常。
通常,您应该使用NSObject*
或id<NSObject>
优先于id
,它至少确认返回的对象是Cocoa对象,因此您可以安全地在其上使用诸如keep / release / autorelease之类的方法。
Often you should use NSObject*
而不是id
。通过指定,NSObject*
您实际上是在明确地说该对象是NSObject。对对象的任何方法调用都将导致警告,但只要该对象确实响应了该方法调用,就不会出现运行时异常。该警告显然很烦人,因此id
更好。粗略地讲id<MKAnnotation>
,例如,可以说得更具体些,在这种情况下,这意味着无论对象是什么,它都必须符合MKAnnotation协议。
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 *
键入的变量绝对可以成为方法调用的目标-这是一个警告,而不是错误。不仅如此,您还可以执行以下操作:int i = (int)@"Hello, string!";
并继续执行:printf("Sending to an int: '%s'\n", [i UTF8String]);
。这是一个警告,而不是错误(并非完全建议,也不是可移植的)。但是您可以执行这些操作的原因都是基本的
我的理解是id表示一个对象的指针,而void *可以指向任何对象,只要将其转换为要使用的类型即可
除了已经说过的以外,与集合相关的对象和指针之间也有区别。例如,如果要在NSArray中放入某些内容,则需要一个对象(“ id”类型),并且不能在其中使用原始数据指针(“ void *”类型)。您可以使用[NSValue valueWithPointer:rawData]
转换void *rawDdata
为“ id”类型,以便在集合中使用它。通常,“ id”更灵活,并且具有与附加到它的对象有关的更多语义。这里还有更多示例说明了Objective C的id类型。
id
假定an 可以响应-retain
and-release
,而avoid*
对于被调用者是完全不透明的。您不能将任意指针传递给-performSelector:withObject:afterDelay:
它(保留对象),也不能假定+[UIView beginAnimations:context:]
将保留上下文(动画委托应保留该上下文的所有权; UIKit保留动画委托)。