Now every self-respecting brogrammer out there should have at least experimented with developing iOS apps, and Apple has put a lot of time into making their development environment extremely friendly and usable (although sometimes less than stable). With that said though there have still been countless times when I’ve been sitting, sipping on my venti strawberry-smoothie with double whey protein from Starbucks, while working on my latest iPhone app and been beating my head against the wall thinking to myself: “Bro! How do I debug this stupid crash?!” So this article will contain a collection of the most useful debugging features I’ve found in XCode.
Enabling zombie objects is probably one of the most useful debugging features I’ve used in the entire XCode environment. These little guys make tracking over-released objects much MUCH easier, by giving a concise error printout that states the class and memory location of the object that was over-released.
To enable zombie objects, open your scheme editor either by opening the “Product” menu and selecting “Edit Scheme” (or by using the hotkey ⌘< ) next, select the diagnostics tab of the scheme editor and check “Enable Zombie Objects” that’s really all there is to it.
Now I’ve disabled automated reference counting (ARC) in my examples to make over-releases, exceptions and crashes easier to reproduce, but even with ARC enabled, over-released objects and memory related crashes can still occur. Now imagine some careless developer has gone and done something like this.
If you were to run this code your view object would be over-released and your app would crash in the main function and you would see something like this.
Enable zombie objects and all of a sudden your debugger is looking something like this.
This may not seem like much in such a small example but in any decently sized project those few lines of debug output can be a goldmine of information.
One thing XCode loves to do when your application crashes or throws an exception, is take you all the way to the main function, as you can see in the previous example. Wouldn’t it be nice if there was a way for the debugger to break on the line where the exception was thrown? Well we’re in luck, because there is a way. XCode has a nifty feature called exception breakpoints, that lets you put a breakpoint down that will only be hit in the case of an exception being thrown. You can either tailor these breakpoints to specific exceptions or just have the breakpoint catch all exceptions.
To enable one of these breakpoints go to your breakpoint explorer and hit the “add breakpoint” button on the bottom left. Then select “Add Exception Breakpoint” and make sure it is set to catch all exceptions.
Now instead of breaking on your main function the debugger will break at the line the exception was thrown.
This will give you a good starting point for debugging thrown exceptions and reduce the time you spend sifting through files of code trying to trace an exception back to where it was thrown.
The XCode static analyzer is a great tool for finding problems that wouldn’t show up as compiler warnings or errors like potential memory leaks and dead stores (unused values assigned to variables). This can be a great asset in improving memory usage, and performance, as well as overall stability and code quality in your application. To run a static analysis, open the product menu in XCode and select the “Analyze” option, or use the ⌘ shift B hotkey.
As you can see in the screenshot below a static analysis will catch any potential problems in your application and display them as blue warnings.
You can also set up your project to automatically run the static analyzer whenever you compile your application by opening your project file and setting the “Run Static Analyer” option to YES, as shown below.
The last tip I have for you today is on conditional breakpoints. These are just regular old breakpoints that will only break when a certain condition on a variable is met. These little guys are great if you want to catch a certain value say on a variable in a loop without having to break on every iteration, or while hunting down fringe case issues that don’t always occur. To set a conditional breakpoint, just set a regular breakpoint then right click on it select “Edit Breakpoint”. This will open up the breakpoint editor where you can set your break condition (as well as a couple other breakpoint settings), then just click the “Done” button. It really is that easy!
- -[NSObject(NSObject) doesNotRecognizeSelector:]