views:

219

answers:

2

I've just been bitten by an annoying bug that was made obscure by the "send message to nil is ok" behaviour in Objective-C.

I've seen http://stackoverflow.com/questions/156395/sending-a-message-to-nil, and the consensus seems to be 'thats how we roll' in Objective-C.

Now, maybe I don't have enough experience in Objective-C, but it seems like it would be useful to trap this, because I can't think of a good reason why this should be happening most of the time. However, It could just be a coding idiom I'm not used to yet.

So other than checking for nil everywhere like so:

assert( object != nil );
[object message];

Is there a way to make the runtime trap this condition, and warn when object is nil?

+4  A: 

You could use a ObjC undocumented trick or dtrace (see the comments for the dtrace solution).

pid$1::objc_msgSend:entry
/arg0==0/
{
  ustack();
}
diciu
Awesome. When my eyes stop bleeding I'll give it a try :-)
Justicle
+3  A: 

nil messaging is used very commonly in ObjC. Folks can fight over whether this is good or bad; it's just something you have to get used to. If you try to break it with tricks, then you're going to break Cocoa because Cocoa uses it. There are some tricks (like diciu posted) that will make it possible to debug in situations where you suspect nil messaging but just can't seem to find it. But you can't just leave those in your code (and the blog post above makes that clear). nil messaging is just too common inside the frameworks.

To your original point, though, compare:

- (void)doSomethingWith:(id)x {
    NSAssert(x != nil, @"Don't pass me nil");
    [x something];
}

vs.

void Bar::DoSomething(Foo *x) {
    assert(x != NULL);
    if (x != NULL) {
       x.something;
    }
}

In both cases, you need to test, and in both cases the compiler won't warn you if you fail to test. The only difference is in what cases you crash/assert. Personally, I write macros around NSAssert() that make it always print a log message if it fails. It just only crashes in Debug. That way when a customer sends me logs, I can see what assertions failed.

Rob Napier
Thanks Rob, I merely included the hard assert for brevity - I'm not a fan of release-build assert crashes. I think the whole send-message-to-nil thing is something I'll just get used to. Still, its worth asking and learning a bit more about what's going on under the hood - everybody wins!
Justicle