191

In observeValueForKeyPath:ofObject:change:context: - why do the docs use NULL instead of nil when not specifying a context pointer?

jrturton
  • 118,105
  • 32
  • 252
  • 268
erikprice
  • 6,240
  • 3
  • 30
  • 40

5 Answers5

232

nil should only be used in place of an id, what we Java and C++ programmers would think of as a pointer to an object. Use NULL for non-object pointers.

Look at the declaration of that method:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
    change:(NSDictionary *)change context:(void *)context

Context is a void * (ie a C-style pointer), so you'd definitely use NULL (which is sometimes declared as (void *)0) rather than nil (which is of type id).

VisioN
  • 143,310
  • 32
  • 282
  • 281
Paul Tomblin
  • 179,021
  • 58
  • 319
  • 408
  • 3
    But since the type of `context` in `observeValueForKeyPath:ofObject:change:context:` is `void *`, doesn't that mean that the data passed as the `context` could be an object pointer? I would think that to be a common case. That's why I'm confused as to why the docs always use `NULL` instead of `nil`. – erikprice Feb 17 '09 at 16:38
  • 2
    The type of context: in that method is "void *". "nil" is not a "void *", but NULL is. – Paul Tomblin Feb 17 '09 at 16:47
  • So is it correct to deduce from this discussion that we *cannot* pass an object pointer (aka, something that can be typed as `nil`) when we pass this message to the object implementing NSKeyValueObserving? Because object pointers cannot be of type `void *` ? – erikprice Feb 17 '09 at 17:27
  • To be honest with you, I don't know if you can cast an id into a void*. – Paul Tomblin Feb 17 '09 at 17:57
  • 3
    You can. void * is any pointer. Nonetheless, you are absolutely right that NULL is the correct constant there. – Peter Hosey Feb 17 '09 at 18:16
  • This gets to the meat of my question - why is NULL the correct constant in this case, rather than nil? Given that NULL and nil both have the same "value", what I want to understand is the reasons for using one vs the other - is it intended that context not be an object pointer? It seems deliberate. – erikprice Feb 17 '09 at 18:46
  • 3
    They said void *. NULL is for void * and nil is for id. Therefore, you pass NULL. If you pass nil, you are lying to your reader, who will think this method takes an id. – Peter Hosey Feb 17 '09 at 18:50
  • Peter's got it exactly right - if a function expects a type, and you want to pass a null, pass in the correct null type, not one that just happens to be a subset or have the same internal representation. – Paul Tomblin Feb 17 '09 at 18:53
  • 13
    Or to think of it another way, NULL is a broader type, and nil is a subset of NULL. In general, use the broadest type you can get away with (ie in Java, write your method to expect a Collection instead of a Vector, unless you need something specific from Vector) – Paul Tomblin Feb 17 '09 at 18:56
  • That makes good sense. Thanks to both of you for humoring my persistent questions. – erikprice Feb 17 '09 at 21:11
  • I'm glad you understand it better now. – Paul Tomblin Feb 17 '09 at 21:49
  • As someone pretty new to the C family of languages, I didn't understand this answer until I also read the answer to this question: http://stackoverflow.com/questions/1304176/objective-c-difference-between-id-and-void Perhaps a link to that question would be a helpful addition to this answer? The semantic distinction between 'C-style pointer' and 'pointer to an object' was - to me at least - not obvious from this answer. – Mark Amery Jun 28 '13 at 16:45
  • Do you know what is the case when a method receives a pointer to a pointer, i.e.: ...withError: (NSError **)error; ? – Daniel Sanchez Feb 11 '15 at 15:44
  • @DanielSanchez Very late answer, but still useful for someone that may have your same question, as I once did. The double-pointer i.e. pointer to a pointer allows the callee to assign the value that NSError points to such that the caller can observe the effects. It's a simple way to return multiple values from a method without writing ugly bundling code. – cincy_anddeveloper Jul 08 '20 at 15:32
67

They're technically the same thing (0), but nil is usually used for an Objective-C object type, while NULL is used for c-style pointers (void *).

Marc Charbonneau
  • 40,399
  • 3
  • 75
  • 82
  • 8
    Also, `NULL` is differently defined than `nil`. `nil` is defined as `(id)0`. `NULL` isn't. –  Aug 18 '11 at 15:40
  • 16
    @WTP if you read through MacTypes.h, it declares #define nil NULL – jbat100 Nov 27 '11 at 13:57
  • 1
    That is very interesting. It seems it does not matter than other than for style points. It's like YES/TRUE and NO/FALSE. – Brennan May 01 '13 at 19:49
  • 1
    @Brennan, That's not entirely true, just because nil is defined as NULL doesn't mean there's some other hidden implementation behind the scenes. For example, IBAction is defined as void but it has a different meaning when using interface builder when displaying methods to attach to actions on buttons and such. – Micaiah Wallace Mar 13 '15 at 15:49
54

They're technically the same thing and differ only in style:

  • Objective-C style says nil is what to use for the id type (and pointers to objects).
  • C style says that NULL is what you use for void *.
  • C++ style typically says that you should just use 0.

I typically use the variant that matches the language where the type is declared.

Andrew
  • 1,337
  • 12
  • 11
15

NULL is the C equivalent of nil, a pointer to nothing;

where nil is zero typed as id,

NULL is zero typed as void*.

One important point you can’t send a message to NULL. So it is preferred to use nil in objective-C at many places.

4

They almost are the same thing except,

nil is used in an Objective-C style. where NULL is for C type pointers and is typdef'ed to (void *).

dan14941
  • 332
  • 3
  • 16
  • 1
    Isn't this pretty much a repeat of [this existing answer](http://stackoverflow.com/questions/557582/null-vs-nil-in-objective-c/557607#557607)? – Pang Feb 02 '16 at 01:46