Learn Objective-C on the Mac - Mark Dalrymple [121]
■ The debugger contains a command-line interface (a version of the gdb command that is standard on UNIX-based operating systems) which lets you all the functionality mentioned before, as well as execute arbitrary code and examine the results. You can call C functions and Objective-C methods by typing their names just as you would in your source code, and use values from the running program’s variables as message recipients and parameters.
For more detailed information on using the Xcode debugger, see the Xcode Debugging Guide included with the Xcode documentation.
In Xcode, open the Breakpoints view by selecting Run➤Show➤Breakpoints or by pressing ⌘B. This opens the Breakpoints window (see Figure 12-1).
Figure 12-1. Xcode’s Breakpoints window, showing some of the authors’ favorite global breakpoints
On the left side of the window, you’ll see a hierarchy of all the breakpoints you’ve defined, including selections from each open project as well as a list of global breakpoints that will be used for every project you run. On the right you see the breakpoints that fit the left-hand-side selection. We’re going to add a symbolic breakpoint, which means we’re using the name of a method or function instead of specifying a source code line, to the Global Breakpoints group, so it will be present in every project you run. Remember, every raised exception is the result of a bug, probably yours, and you’ll want to take every chance you get to stop and see where it’s coming from.
Double-click in the space where it says “Double-Click for Symbol,” type in objc_exception_throw, and press Enter. This configures a new breakpoint that will stop whenever the program enters the objc_exception_throw function. The Breakpoint column shows the name of the symbol you entered (or, if you set a breakpoint directly in a source code file, the name of the method or function containing the line, along with the breakpoint number), and the Location column shows the name of the library where the symbol is located, or the name of the source code file, if it’s available. There are a number of options available for each breakpoint you configure, but the only one we’ll point out right now is the column whose header contains just a checkmark. Clicking a breakpoint’s checkbox in this column lets you disable and re-enable the breakpoint.
Now restart the ExceptionCity application by choosing Run➤Debug from the menu, first quitting it if it’s still running. This time, when the application hits the problematic code, it will halt execution where the exception is raised. Figure 12-2 shows roughly what Xcode looks like at this point.
Figure 12-2. Xcode stops at a breakpoint.
The upper left shows the call stack, with the location of our breakpoint (objc_exception_throw) at the top and all callers below. Note that the frames for which we have source code available are rendered with black text, while the frames that are stuck in closed-source libraries are shown with gray text. The grayed-out frames are still accessible, but only in the form of assembly language.
The middle left shows all available variables and register values, where you can see some simple values immediately. The upper right shows the source code or compiled assembly code for the chosen stack frame. The bottom view shows you the gdb console interface, where you can both view your program’s output (generated by NSLog etc), and enter commands at the gdb prompt. If you’re not seeing that bottom view, you can make it appear by selected Run➤Console from the menu.
At this point, having halted right at the start of the function that’s used to raise an exception, it would be interesting to see what the exception is. But how? All we see is a pile of assembly code, no variable names