NSArray being one of the most frequently used Cocoa classes and being out of bounds being one of the most common errors one would get with an array, I'd have thought that the NSRangeException which NSArray promises to throw if an out of bounds error occurs would trigger the debugger (or, alternatively, the application to crash in non-debugging mode). However, it does not do so. All that happens is that you get this in your Run Log and your stack unwinds:
The first question that should come to mind is, "What the hell is actually going on? Is the promised NSRangeException being raised at all or is the documentation just lying? Giving the documentation the benefit of the doubt and assuming that it is being raised, what in the world is happening to it before it reaches us?" This kind of reasoning led me to search for ways to catch exceptions in the debugger. Some Google searching revealed that setting a symbolic breakpoint at -[NSException raise] might do the trick. So, I did. And it didn't. Cleanly flew by that breakpoint as if it was a man raising his kilt to hitch a ride.
What next? Look for an even more basic call to catch exceptions. Going by the fact that most fundamental Objective-C runtime methods eventually go into C functions and going by the example of objc_msg_send, I discovered objc_exception_throw and set a breakpoint on it. Worked like a charm! And now I have that breakpoint always set because I, like any sane developer, wants to catch his exceptions before they reach the end-user.
Incidentally, why the exception was not being caught by setting a breakpoint at -[NSException raise] now came to me with breathtaking obviosity ("obviousness" just isn't cool enough). I looked into the documentation for NSException once more and looked at the stack trace once more (the stack trace that now appeared thanks to my breakpoint). NSException, as it turns out, has three methods which can be called to raise exceptions, and, apparently the other two (+raise:format: and +raise:format:arguments:) do not all eventually call into -raise. Now here's the most ludicrous thing about this affair; read this bit from the documentation for -raise:
*** -[NSCFArray objectAtIndex:]: index (2) beyond bounds (2)The fact that such a basic but critical error (who knows in how many devious ways an application could mess with your data once it has a bad state that made it go out of bounds?!) defaults to being silently acknowledged and subsequently ignored unnerves me, and frankly, it annoys me, because, just like any other developer trying to make a half decent program, what you want to do at that point is to jump to the stack trace and see what went wrong. Now, since we're very unlikely to convince Apple to change basic functionality it hasn't touched in about eight years, it's time for workarounds.
The first question that should come to mind is, "What the hell is actually going on? Is the promised NSRangeException being raised at all or is the documentation just lying? Giving the documentation the benefit of the doubt and assuming that it is being raised, what in the world is happening to it before it reaches us?" This kind of reasoning led me to search for ways to catch exceptions in the debugger. Some Google searching revealed that setting a symbolic breakpoint at -[NSException raise] might do the trick. So, I did. And it didn't. Cleanly flew by that breakpoint as if it was a man raising his kilt to hitch a ride.
What next? Look for an even more basic call to catch exceptions. Going by the fact that most fundamental Objective-C runtime methods eventually go into C functions and going by the example of objc_msg_send, I discovered objc_exception_throw and set a breakpoint on it. Worked like a charm! And now I have that breakpoint always set because I, like any sane developer, wants to catch his exceptions before they reach the end-user.
Incidentally, why the exception was not being caught by setting a breakpoint at -[NSException raise] now came to me with breathtaking obviosity ("obviousness" just isn't cool enough). I looked into the documentation for NSException once more and looked at the stack trace once more (the stack trace that now appeared thanks to my breakpoint). NSException, as it turns out, has three methods which can be called to raise exceptions, and, apparently the other two (+raise:format: and +raise:format:arguments:) do not all eventually call into -raise. Now here's the most ludicrous thing about this affair; read this bit from the documentation for -raise:
All other methods that raise an exception invoke this method, so set a breakpoint here if you are debugging exceptions.Wow, just outright lying. Very spiffy, Apple, very spiffy indeed. Undocumented exceptions about exceptions. Is this supposed to be some sort of geek humor? हे भगवान!
2 comments

