Learn Objective-C on the Mac - Mark Dalrymple [122]
Look familiar? That is, of course, the same text we saw in the output earlier on. Knowing that we have access to the NSException here, we can make use of gdb’s live Objective-C method execution to ask it some more things:
Here we see that the reason method’s return value is the same as the description return value, but the name method returns the name, which you may recall is typically used as a sort of type or category for the exception. In this case, we’re looking at one of the most frequently encountered exception types in Cocoa: NSInvalidArgumentException.
NSInvalidArgumentException
This exception can in theory be raised by any method which determines that its parameters are invalid in some way. In practice, there are two typical situations where most Cocoa developers will encounter this at some point, and we’ve just hit the first. Remember that our code loops through all the elements in an array, and tries to call the length method on each:
The problem arises when trying to call length on an object that doesn’t have such a method. Our code tries calling the length method on NSCFNumber (the concrete subclass of NSNumber that happens to be used when we create an NSNumber in the usual way), and that class doesn’t implement that method, all of which we can reasonably deduce from the exception’s reason. We could split hairs now, and complain that Apple really should use a different exception name here that would clearly tell us that the exception is related to a method name, but this seems to be what we’re stuck with.
In any case, we can explore further by using the graphical debugger in Xcode. In the table showing the call stack, click on the line labeled “-[ExceptionCityAppDelegate invalidArgumentException_unrecognizedSelector]” to see the last piece of our code that was being executed before the exception was raised. The text editor switches to a view of the relevant source code file, and the variable view now shows the variables available to us at that point in the program (see Figure 12-3).
Figure 12-3. Choosing a different entry in the call stack gives us access to a different part of our running program. Note that the command-line interface at the bottom shows commands that were executed at the top level of the call stack, inside objc_exception_throw. If you entered the same commands with the current stack frame in focus, $eax would have a different value.
Based on the information we’ve gotten about the exception and what part of our code triggered it, it’s up to us to figure out what the problem is. We can even take additional steps here to examine the current state of our program, such as printing out summary information for the object that the for loop is currently looking at, by typing po component. You can also hover the mouse over a variable in your source code, and a sort of tooltip will appear, where you can see the object’s value and examine its structure further. In this case it’s pretty simple: our array contains an NSNumber, which doesn’t have a length method.
At this point, we have to decide how to fix the problem. We still want to implement the same basic algorithm which adds the lengths of the character strings for each component, we just want to make it so that the value of the NSNumber (in this case, 3) is converted to a string (@“3”). Here we can make use of the description