Debug iOS Applications in Six Easy Steps

Need some background on how to debug iOS? I wrote this post for Raygun’s blog.


In this tutorial, we’ll debug an iOS application with Apple’s Xcode. Xcode is a robust environment for developing and troubleshooting iOS applications. We’ll see how we can use it, alongside Raygun’s iOS Crash Reporting, to quickly address an application deficiency.

We’ll follow six steps to examine a simple application and isolate and fix a bug.

  1. Setup a sample project
  2. Analyze a Raygun debug report
  3. Explore Xcode’s debugging tools for iOS
  4. Set a breakpoint in Xcode
  5. Run the application with a breakpoint
  6. Isolate the bug and fix it

This tutorial requires a macOS computer with Xcode installed. We’ll be using the current version of Xcode at the time of this writing, which is version 10. We’ll write the sample application in Objective-C, but all of the debugging steps are valid for a Swift application, too. The source code for this project is available here on Github.

So, let’s get started!

Step 1: sample project

We’ll use a single view iOS application for this tutorial. The single view has a button with text that changes for each press.

If you want to follow along, you’ll need to register for a Raygun account here. After you check out the project, add your Raygun API (Application Programming Interface) key to didFinishLaunchingWithOptions in AppDelegate.m

You can find complete instructions for setting up an iOS application here. You can follow this tutorial with your application if you prefer.

Here is the sample application’s startup view.

Debug iOS main view Each time you tap the button, the display text changes. After a few presses, the application crashes. Imagine that this application has been released to the App Store and was already approved. You need to track down the bug fast!

Step 2: analyze the Raygun debug report

Fortunately, you integrated your application with Raygun Error Monitoring and Crash Reporting, so you can use the information to get an idea of where to look for the bug.

First, let’s look at the error summary.

iOS debug error summary
(click to expand image)

Since we forced the error now, we don’t need the date and time. But in the event of any errors happening in deployed applications, the date and time can be advantageous.

The class name and error message tell us a lot about the error. NSRangeException indicates that the code exceeded the bounds of a data structure, and the report suggests a subscript out of range is causing the crash.

Raygun also provides a backtrace for the error.

iOS debug backtrace

Since we’re dealing with an uncaught exception, the backtrace only provides us with a rough idea of where the error is occurring; somewhere in UIKit. So, we’ll need to run the application in a debugger to find the exact location.

Step 3: iOS debugging with Xcode

Xcode provides iOS developers with an integrated environment for developing, testing, and debugging iOS applications. The simulator supports all current iOS platforms. You can install and run applications with a single click, and the environment has integrated support for the lldb debugger.

xcode iOS debug

So, you can debug your application on your development desktop. Let’s start with replicating the error in the simulator.

iOS debug run button

We want to be sure we run a debug build, so start by holding the option key and clicking the run icon on the upper left-hand side of Xcode. This brings up the run options dialog.

iOS debug run options

Make sure that you have Run selected on the left-hand side, and debug build enabled on the right. Now, click on the run button. After the build completes, the application will start in the simulator.

Debug iOS main view

Next, click the iOS app’s button until the application throws the exception and the debugger comes up in Xcode.

iOS debug window

On the left-hand side, the debug navigator displays the application threads. Xcode highlights main in thread #1 since uncaught exceptions “bubble up” to that location in the application. In the editor pane, Xcode highlights that function in main.m. Xcode shows us that a SIGABRT was thrown inside main. Down at the bottom of Xcode lldb’s command line interface is available. We’re going to control it from the GUI (Graphical User Interface).

Finally, click the stop button, next to run, to stop the debug session.

Raygun already told us that the application has an uncaught exception, so we haven’t learned anything new about the bug yet. Now, let’s use Xcode to catch the exception and discover where it’s coming from.

Step 4: set exception breakpoint

So, go to the Debug menu, select Breakpoints and Create Exception Breakpoint.

iOS debug create exception breakpoint

Xcode brings up the breakpoint navigator on the left, and a popup will appear.

iOS debug exception popup

The default is to break on both C++ and Objective C exceptions and to stop the debugger where they are thrown. This will take us to where the problem occurs. Next, click anywhere to dismiss the popup and accept the defaults.

Step 5: run the application with breakpoint

Now, rerun the application and force the error.

iOS debug window with breaks

The debugger stopped when the application generated the exception and highlighted the line of code that is responsible.

iOS debug broken code

Just as you might expect from the Raygun error report, the code references an array. The problem is clear from viewing the highlighted line. We’re incrementing the array index without checking bounds. If you look down in the debug window in Xcode, you can see that counter somehow made it to a value of five when the array is only four elements long. The application should have crashed sooner than it did.

But what if the problem was more difficult to isolate? Let’s add one more breakpoint and step through the application again.

Step 6: isolate the bug and fix it

First, stop the debug session.

Next, double-click next to the offending line in the source code to bring up a breakpoint dialog popup.

iOS debug break on counter

Add a condition for the breakpoint; counter > 3.

Rerun the application, and when you force the error, it will stop before iOS throws the exception. The array index and the increment are on the same line of code. So, continuing after the breakpoint will still result in iOS throwing the exception. This breakpoint makes the bug clear, and we can see how conditional breaks can help isolate a thorny problem.

There are several ways to fix this bug. Most of the better ones involve a different design, but let’s go for a quick fix.

By checking the array bounds before we increment the counter, we never exceed the array length. Rerun the application, and the crash is gone.

Next steps

Apple’s XCode development tool simplifies debugging iOS applications. It provides integrated support for an advanced debugger as well as GUI-based shortcuts for common tasks like adding breakpoints. Fortunately, you can also rely on their simulator to accurately emulate the full set of iOS devices since Apple controls the platform. Once you’ve verified an issue is addressed in the simulator, you can push to local devices and test there too.

Of course, with Raygun, you have an extra layer of protection for detecting, diagnosing, and eliminate iOS errors. The Raygun report in this example told us what the failure was, and made it much easier to isolate. Raygun’s smart alerts and error grouping means you never miss a bug in your app again. Read more about iOS crash reporting here.

 

 

 

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Proudly powered by WordPress | Theme: Baskerville 2 by Anders Noren.

Up ↑

%d bloggers like this: