id和 和有什么不一样void *?
id
void *
void *表示“对具有无类型/未知内容的一些随机内存块的引用”
id表示“对未知类的一些随机 Objective-C 对象的引用”
还有其他语义差异:
在 GC Only 或 GC Supported 模式下,编译器将为 type 的引用发出写屏障id,但不会为 type void *。在声明结构时,这可能是一个关键的区别。如果实际上是一个对象,则声明 iVarvoid *_superPrivateDoNotTouch;将导致对象的过早收获。_superPrivateDoNotTouch不要那样做。
void *_superPrivateDoNotTouch;
_superPrivateDoNotTouch
尝试在void *类型的引用上调用方法会引发编译器警告。
尝试调用id类型上的方法只会在被调用的方法没有在@interface编译器看到的任何声明中声明时发出警告。
@interface
因此,永远不应将对象称为void *. 同样,应该避免使用id类型化变量来引用对象。尽可能使用最具体的类类型引用。甚至NSObject *更好,id因为编译器至少可以针对该引用提供更好的方法调用验证。
NSObject *
一个常见且有效的用途void *是作为通过其他 API 传递的不透明数据引用。
考虑以下sortedArrayUsingFunction: context:方法NSArray:
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 而言,它是一大块不透明的指针大小的数据,您可以随意将其用于您想要的任何目的。
context
如果语言中没有闭包类型的特性,这是用函数携带大量数据的唯一方法。例子; 如果您希望 mySortFunc() 有条件地排序为区分大小写或不区分大小写,同时仍然是线程安全的,您将在上下文中传递区分大小写的指示符,可能会在进出时进行强制转换。
脆弱且容易出错,但这是唯一的方法。
块解决了这个问题——块是 C 的闭包。它们在 Clang 中可用——http: //llvm.org/并且在雪豹中普遍存在(http://developer.apple.com/library/ios/documentation/Performance /参考/GCD_libdispatch_Ref/GCD_libdispatch_Ref.pdf)。