172

What is the difference between id and void *?

mk12
  • 25,873
  • 32
  • 98
  • 137

7 Answers7

243

void * means "a reference to some random chunk o' memory with untyped/unknown contents"

id means "a reference to some random Objective-C object of unknown class"

There are additional semantic differences:

  • Under GC Only or GC Supported modes, the compiler will emit write barriers for references of type id, but not for type void *. When declaring structures, this can be a critical difference. Declaring iVars like void *_superPrivateDoNotTouch; will cause premature reaping of objects if _superPrivateDoNotTouch is actually an object. Don't do that.

  • attempting to invoke a method on a reference of void * type will barf up a compiler warning.

  • attempting to invoke a method on an id type will only warn if the method being called has not been declared in any of the @interface declarations seen by the compiler.

Thus, one should never refer to an object as a void *. Similarly, one should avoid using an id typed variable to refer to an object. Use the most specific class typed reference you can. Even NSObject * is better than id because the compiler can, at the least, provide better validation of method invocations against that reference.

The one common and valid use of void * is as an opaque data reference that is passed through some other API.

Consider the sortedArrayUsingFunction: context: method of NSArray:

- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context;

The sorting function would be declared as:

NSInteger mySortFunc(id left, id right, void *context) { ...; }

In this case, the NSArray merely passes whatever you pass in as the context argument to the method through as the context argument. It is an opaque hunk of pointer sized data, as far as NSArray is concerned, and you are free to use it for whatever purpose you want.

Without a closure type feature in the language, this is the only way to carry along a hunk of data with a function. Example; if you wanted mySortFunc() to conditionally sort as case sensitive or case insensitive, while also still being thread-safe, you would pass the is-case-sensitive indicator in the context, likely casting on the way in and way out.

Fragile and error prone, but the only way.

Blocks solve this -- Blocks are closures for C. They are available in Clang -- http://llvm.org/ and are pervasive in Snow Leopard (http://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/GCD_libdispatch_Ref.pdf).

Snowcrash
  • 80,579
  • 89
  • 266
  • 376
bbum
  • 162,346
  • 23
  • 271
  • 359
  • Additionally, I'm pretty sure that an `id` is assumed to respond to `-retain` and `-release`, whereas a `void*` is completely opaque to the callee. You can't pass an arbitrary pointer to `-performSelector:withObject:afterDelay:` (it retains the object), and you can't assume that `+[UIView beginAnimations:context:]` will retain the context (the animation delegate should maintain ownership of the context; UIKit retains the animation delegate). – tc. Oct 13 '10 at 20:02
  • 3
    No assumptions can be made about what an `id` responds to. An `id` can easily refer to an instance of a class that does not inherent from `NSObject`. Practically speaking, though, your statement best matches real world behavior; you can't mix non-`` implementing classes with Foundation API and get very far, that is definitely for sure! – bbum Oct 13 '10 at 22:42
  • 2
    Now `id` and `Class` types are being treated as [*retainable object pointer*](http://clang.llvm.org/docs/AutomaticReferenceCounting.html#objects) under ARC. So the assumption is true at least under ARC. – eonil Dec 05 '12 at 11:14
  • What's "premature reaping"? – Bradley Thomas Jan 30 '17 at 19:28
  • 1
    @BradThomas When a garbage collector collects memory before the program is done with it. – bbum Jan 30 '17 at 22:01
21

id is a pointer to an objective C object, where as void* is a pointer to anything.

id also turns off warnings related to calling unknown mthods, so for example:

[(id)obj doSomethingWeirdYouveNeverHeardOf];

will not give the usual warning about unknown methods. It will, of course, raise an exception at run time unless obj is nil or really does implement that method.

Often you should use NSObject* or id<NSObject> in preference to id, which at least confirms that the object returned is a Cocoa object, so you can safely use methods like retain/release/autorelease on it.

Caleb
  • 124,013
  • 19
  • 183
  • 272
Peter N Lewis
  • 17,664
  • 2
  • 43
  • 56
  • 2
    For method invocations, a target of type (id) will generate a warning if the targeted method has not been declared anywhere. Thus, in your example, doSomethingWeirdYouveNeverHeardOf would have had to have been declared somewhere for there not to be a warning. – bbum Aug 20 '09 at 06:26
  • You're wuite right, a better example would be something like storagePolicy. – Peter N Lewis Aug 21 '09 at 01:03
  • @PeterNLewis I disagree on `Often you should use NSObject*` instead of `id`. By specifying `NSObject*` you are actually explicitly saying that the object is an NSObject. Any method call to the object will result in a warning, but no runtime exception for as long as that object indeed responds the method call. The warning is obviously annoying so `id` is better. Of coarse you can then be more specific by for example saying `id` ,which in this case means whatever the object, it must conform to the MKAnnotation protocol. – pnizzle May 04 '17 at 07:09
  • 1
    If you're going to use id, then you can just as well use NSObject*. Which then allows you to use any of the methods in the MKAnnotation and any of the methods in NSObject (ie, all objects in the normal NSObject root class hierarchy), and get a warning for anything else, which is much better than no warning and a runtime crash. – Peter N Lewis May 04 '17 at 23:32
8

If a method has a return type of id you may return any Objective-C object.

void means, the method won't return anything.

void * is just a pointer. You won't be able to edit the content on the address the pointer points to.

fphilipe
  • 9,739
  • 1
  • 40
  • 52
  • 3
    As it applies to the return value of a method, mostly right. As it applies to declaring variables or arguments, not quite. And you can always cast a (void *) to a more specific type if you want to read/write the contents -- not that it is a good idea to do so. – bbum Aug 20 '09 at 06:31
8

id is a pointer to an Objective-C object. void * is a pointer to anything. You could use void * instead of id, but it's not recommended because you'd never get compiler warnings for anything.

You may want to see stackoverflow.com/questions/466777/whats-the-difference-between-declaring-a-variable-id-and-nsobject and unixjunkie.blogspot.com/2008/03/id-vs-nsobject-vs-id.html.

Community
  • 1
  • 1
Michael
  • 4,700
  • 9
  • 35
  • 42
  • 1
    Not quite. (void *) typed variables cannot be the target of method invocations at all. It results in "warning: invalid receiver type 'void *'" from the compiler. – bbum Aug 20 '09 at 06:24
  • @bbum: `void *` typed variables most definitely can be the target of method invocations- it's a warning, not an error. Not only that, you can do this: `int i = (int)@"Hello, string!";` and follow up with: `printf("Sending to an int: '%s'\n", [i UTF8String]);`. It's a warning, not an error (and not exactly recommended, nor portable). But the reason why you can do these things is all basic C. – johne Aug 22 '09 at 22:17
  • 1
    Sorry. You are correct; it is a warning, not an error. I just treat warnings as errors always and everywhere. – bbum Aug 23 '09 at 01:48
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;

The above code is from objc.h, so looks like id is an instance of objc_object struct and isa pointer can bind with any Objective C Class object, while void* is just an untyped pointer.

jack
  • 731
  • 7
  • 8
2

My understanding is that id represents a pointer to an object while void * can point to anything really, as long as you then cast it to the type you want to use it as

hhafez
  • 38,949
  • 39
  • 113
  • 143
  • If you are casting from (void *) to some object type, including id, you are very likely doing it wrong. There are reasons to do so, but they are few, far between, and almost always indicative of a design flaw. – bbum Aug 20 '09 at 06:27
  • 1
    quote "there are reasons to do so, but they are few,far between" true that. It depends on the situation. However I wouldn't make a blanket statement like "you are very likely doing it wrong" with out some context. – hhafez Aug 20 '09 at 06:36
  • I would make a blanket statement; had to hunt down and fix too many damned bugs because of casting to the wrong type with void* in between. The one exception is callback based APIs that take a void* context argument whose contract states that the context will remain untouched between setting up the callback and receiving the callback. – bbum Aug 20 '09 at 06:54
0

In addition to what's already said, there's a difference between objects and pointers related to collections. For example, if you want to put something into NSArray, you need an object (of type "id"), and you can't use a raw data pointer there (of type "void *"). You can use [NSValue valueWithPointer:rawData] to convert void *rawDdata to the "id" type for using it inside a collection. In general "id" is more flexible and has more semantics related to objects attached to it. There's more examples explaining id type of Objective C here.

battlmonstr
  • 5,841
  • 1
  • 23
  • 33