At the core of every engineering process is reiterating and fixing mistakes. For apps, there are a set of basic bugs:
There are many other possible bugs, and reasons for breaking down the code. Apple provides us with a set of tools to go about troubleshooting bugs and figuring out how to fix them.
The main set of debugging skills we'll go over are:
Apple also provides additional tools for testing code and other circumstances:
There are also third-party tools that have been created to aid in coding for iOS:
Additionally, in a perfect world, the tools we are given would work flawlessly, but that is not the case. Xcode, itself, will some times be buggy. Please see this section for common gotchas and possible fixes.
Above everything, always test with an actual device. There is no substitute.
When you attempt to run your code, Xcode may report compiler warnings or errors. These messages will show up in a number of places.
On the toolbar at the top:
On the offending line of code in the editor:
And in the Issues Navigator, on the left:
As you're coding, Xcode will either give you warnings or error signals in the top toolbar and in your editor. They will also show up when your code fails to build. Clicking on the yellow warning or red error symbols in the top toolbar will bring up the Issues Navigator. Clicking on the items that show up in your Issues Navigator will bring up the offending line. It's generally a good rule of thumb to fix even the warnings, though they will not prevent you from compiling a successful build.
Even after writing an app, it doesn't always operate the way we expect it to. Breakpoints are a tool used to better understand the flow and process of how an app works. We use breakpoints to pause the code at a specific line. With breakpoints, we can check what the exact state of the app is at a specific line.
To add a breakpoint, you click to the left of the line of code where you want to pause the app.
You can track where you've added breakpoints across your entire project in the Breakpoints Navigator:
Once you've clicked to the left of the line, the section will be highlighted in blue. In order to disable it, click again. In order to delete it, right click, and select Delete Breakpoint. Note that if the debug flag is gray instead of blue, breakpoints are deactivated. In order to reactivate breakpoints, you can go to the Debug tab in the menu and select "Activate Breakpoints" or use the ⌘Y shortcut.
When you run your app with breakpoints activated, your app should pause when the line of code you've marked is called. In the screenshot above, the breakpoint is added in the viewDidLoad function. Thus when the view controller initially loads, the app will pause.
When you've activated breakpoints, and your app has paused, this bar becomes important:
The buttons allow you to control where you are in the app's flow. You can continue, step line by line, or step into and out of a function.
In the above code:
testing()
on line 20.print("first line of code")
on line 16testing()
to print("blahblah")
on line 24.These actions can be accessed from either the Debugging bar or from the Debug menu of Xcode.
Sometimes your app crashes, but it's not very informative as to where it crashes. Xcode may crash and point you to the autorelease pool in the main method or the AppDelegate file. Neither is very helpful in nailing down why your app just crashed.
However! We can set an exception breakpoint, so that Xcode will break at the exact line of code where the exception is thrown. Click the + on the bottom left of the Breakpoints Navigator, and select Add Exception Breakpoint...
Now that you have an exception breakpoint set, Xcode will pause before throwing an exception error. Depending on the kind of error, this will be very informative or not.
Below is an example of where it would become informative. The variable array clearly does not contain any values, so this will throw an error.
Without the exception breakpoint, Xcode will show you the AppDelegate file in the editor and simply print in the console:
2016-02-12 15:16:27.908 Tip Calculator[27799:1365479] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArray0 objectAtIndex:]: index 2 beyond bounds for empty NSArray'
This is useful, and we can examine the stack trace to figure out where this array is. But with the exception breakpoint, Xcode will pause at line 18 exactly, to let us know something is wrong with this line of code. Now we know exactly where the NSRangeException occurs.
Whenever your app crashes, the Debug Area is where you will get information for what went wrong. This is the view that will automatically show whenever you use breakpoints or log a message with print
.
We've gone over how to set breakpoints to essentially freeze the state of the app, but this doesn't give us much visibility into the code. The Debug Area is how we poke around and get direct information about what the exact state of the app is.
When the app hits a breakpoint, the Variable View shows you all the variables immediately available in the context where the app is paused.
This list lets you know what you can use to console to print out.
From the Variable View, you can do a number of things:
Please see the apple documentation for further advanced functionality.
If we use print("testing")
in our code, "testing" will be printed out in the console area. When an app crashes, the console immediately prints out the error message, exception, and stack trace to help us troubleshoot and understand the crash. When debugging, we use the console to check for error messages and other logging.
The console is mainly used to interact with lldb, the debugger that Xcode utilizes. We can use the console to control the debugger and step through the code, instead of using the bar at the top of the Debug Area.
The two common commands for displaying variable data are p
and po
, or print and print-object.
The print command (p) allows you to print information about an address, a variable, or a method.
The print-object command (po) takes an Objective-C object as its argument, and calls the object's description method.
As we are dealing with UI in an app, not just inputs and outputs, we also find the Debug View Hierarchy to be a useful tool. As you're running your app in Xcode, it's possible to tap on the following button to see how your app is laid out.
The Debug View Hierarchy provides you with a 3D view of the app. You can visually troubleshoot whether the view you're unable to see is:
It's an extremely useful tool.
It's possible that Xcode did not get the memo, and your code does not work properly. Most commonly, this appears to be the case with the Interface Builder. Sometimes this happens with the Simulator.
Common Gotchas:
If nothing seems to work, and you're flat out of ideas, try resetting Xcode.