Cocoa Programming for Mac OS X - Aaron Hillegass [23]
In the debug console, you have full access to all of gdb’s capabilities. One very handy feature is “print-object” (po). If a variable is a pointer to an object, when you po it, the object is sent the message description, and the result is printed in the console. Try printing the newEntry variable.
po newEntry
You should see the result of your description method (Figure 3.12).
Figure 3.12. Using the gdb Console
Exceptions are raised when something goes very wrong. To make the debugger stop whenever an exception is thrown, you will want to add an exception breakpoint. Click the Add button at the bottom of the breakpoint navigator and select Add Exception Breakpoint.... Set the exception type to Objective-C and click Done (Figure 3.13). Disable the existing breakpoint in main() by clicking on the blue breakpoint icon in the breakpoint navigator. The breakpoint will be dimmed when it is disabled.
Figure 3.13. Adding an Exception Breakpoint
You can test this exception breakpoint by asking for an index that is not in an array. Immediately after the array is created, ask it what its first object is:
array = [[NSMutableArray alloc] init];
NSLog(@"first item = %@", [array objectAtIndex:0]);
Rebuild and restart the program. It should stop when the exception is raised.
One of the challenging things about debugging Cocoa programs is that they will often limp along in a broken state for quite a while. Using the macro NSAssert(), you can get the program to throw an exception as soon as the train leaves the track. For example, in setEntryDate:, you might want an exception thrown if the argument is nil. Add a call to NSAssert():
- (id)initWithEntryDate:(NSDate *)theDate
{
self = [super init];
if (self) {
NSAssert(theDate != nil, @"Argument must be non-nil");
entryDate = theDate;
firstNumber = ((int)random() % 100) + 1;
secondNumber = ((int)random() % 100) + 1;
}
return self;
}
Build it and run it. Your code, being correct, will not throw an exception. So change the assertion to something incorrect:
NSAssert(theDate == nil, @"Argument must be non-nil");
Now build and run your application. Note that a message, including the name of the class and method, is logged and an exception is thrown. Wise use of NSAssert() can help you hunt down bugs much more quickly.
You probably do not need your assert calls checked in your completed product. On most projects, there are two build configurations: Debug and Release. In the Debug version, you will want all your asserts checked. In the Release configuration, you will not. You will typically block assertion checking in the Release configuration (Figure 3.14).
Figure 3.14. Disabling Assertion Checking
To do this, bring up the build settings by selecting the lottery project in the project navigator (topmost item). Then select the lottery target, change to the Build Settings tab, and find the Preprocessor Macros item. A quick way to find it is to use the search field at the top of the Build Settings panel. The Preprocessor Macros item will have one item beneath it for each build configuration: Debug and Release. Set the Release item value to NS_BLOCK_ASSERTIONS.
Now, if you build and run the Release configuration, you’ll see that your assertion is not getting checked. (Before going on, fix your assertion: It should ensure that dates are not nil.)
You can change your current build configuration to Release by opening the scheme editor (in the Product menu, click Edit Scheme...). Select the Run action; on the Info panel, change Build Configuration to Release. Now when you build and run your application, it will be built using the Release configuration. Note that the default build configuration for the Archive action is Release. We will discuss build configurations in more detail in Chapter 37.
NSAssert() works only inside Objective-C methods. If you need to check an assertion in a C function, use NSCAssert().
That’s enough to get you started with the debugger. For more in-depth information,