Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Debugging exception thrown in Objective-C and Xcode

I am a long time Microsoft developer and I am new to iPhone development using Xcode. So, I am reading a book and going through examples trying to teach myself how to write an iPhone application using Objective-C. All has been good so far, however, once in a while I run into the generic 'objc_exception_throw' message at runtime. When this happens, the source of this exception is very difficult to find. After some trial and error I found my answer. One of the parameters was misspelled.

As you can see below, I misspelled the 'otherButtonTitles' parameter by leaving out the second 't' in button.

UIAlertView *alert = [[UIAlertView alloc] 
                      initWithTitle:@"Date and Time Selected" 
                      message:message 
                      delegate:nil
                      cancelButtonTitle:@"Cancel"
                      otherButonTitles:nil];

The reason this took me time to find is that the code built successfully. Is this normal behavior for the Objective-C compiler? I am used to having the build fail in the .NET compiler when I make a common syntax error like this. Is there a compiler setting I can change to make the built fail when I make these mistakes?

like image 790
rtemp Avatar asked Apr 02 '09 21:04

rtemp


2 Answers

First and foremost, open ~/.gdbinit (that's the file called .gdbinit in your home directory - yes, starts with a dot) and put this in it:

fb -[NSException raise]
fb objc_exception_throw
fb malloc_error_break

That'll initialize GDB with three default breakpoints, when they occur, GDB will halt your application and show you the stack trace. This is very well integrated with Xcode so you'll be able to nicely walk through your code by clicking stack trace elements as soon as an exception occurs somewhere or a malloc fails.

Then, open the Get Info panel on your project (or select your project (top item in the Groups & Files) and hit cmd-i), go to the Build tab and set your project's Base SDK to Device - iPhone OS [someversion]. Scroll all the way to the bottom and find the GCC 4.0 - Warnings section. There; turn on as many warnings as you feel comfortable with, but make sure to turn on Treat Warnings as Errors (this is the equivalent of GCC_TREAT_WARNINGS_AS_ERRORS). Personally, I have it set to this:

GCC Warning Build Settings
(source: lyndir.com)

You should now be getting compiler warnings for most things you can do wrong in code and the compiler won't let you run the code until you fix them. When things do get past the compiler's nose, you should be able to find the problem easily with GDB breaking at a convenient spot.

You should also look into NSZombie*. These are environment variables that are very handy for early breaking on bad memory allocation or access situations. For instance; wih NSZombieEnabled nothing will truly be released; on dealloc it'll get overwritten with _NSZombie and should you try to access this dealloced memory again (dereferencing a dealloced pointer) you'll get something to break on in GDB, instead of the call going through like normal, only being issued on random data (which, of course, isn't what you wanted). For more info on this, see http://www.cocoadev.com/index.pl?NSZombieEnabled.

like image 122
lhunath Avatar answered Sep 28 '22 22:09

lhunath


Always use the -Werror GCC setting (GCC_TREAT_WARNINGS_AS_ERRORS = YES). You should never have warnings in your code and this is an example where the warning is a critical error.

Also, if you get an objc_exception_throw, switch to the console (Command-shift-R) and look for the first "low" number address.

2009-04-01 13:25:43.385 CrashExample[41720:20b] Stack: (
    2528013804,
    2478503148,
    2528036920,
    2528053460,
    2358032430,
    11076,
    11880,
    816174880,
    345098340,
    145973440,
    816174880,
)

In this case it would be "11076". So type in the console:

info line *11076

That will tell you the line in your code where the exception was thrown.

like image 43
Matt Gallagher Avatar answered Sep 28 '22 22:09

Matt Gallagher