How To Debug iOS Apps in Xcode (I): Debugger and Breakpoints

June 3, 2017 in
How to Debug iOS Apps in Xcode. Getting To Know The Debugger.

How to Debug iOS Applications in Xcode. Getting To Know The Debugger.

Sooner or later, your application will fail and even crash, so you need to know how to debug your code and identify problems. In this tutorial series, you will learn how to Debug iOS Apps in Xcode. Let’s start by getting to know the Debugger (LLDB) and what’s a breakpoint.

Do I Really Need To Know This?

Debugging is one of those topics that scares beginner developers the most. Besides, it definitely does not appear to be the most enjoyable part of developing an iOS Application.

However, if you are serious about becoming an iOS developer, it’s essential that you learn how to debug and fix your applications.

My goal is showing you that not only it’s not as complicated as it seems, but can be quite enjoyable. Let’s start!

How to Debug iOS Apps in Xcode

Before we even get to know the Debugger, it’s important that you know what “debugging” means. Besides, there are a series of terms you need to know.

Basically, debugging means pausing the execution of the program at a certain point, and then reviewing the instructions of that area of code step by step.

The goal is being able to check how data is being modified and operations are being applied, in order to detect a possible bug or a sequence of instructions that can be optimized.

The main concept when debugging any application is the breakpoint. A breakpoint is a mark you set on certain instruction to indicate the debugger that it should stop at that instruction.

You can set as many endpoints as you want in your application. Generally speaking, you would like to add those breakpoints to the places where your code is crashing or your app is not behaving optimally enough.

Thus, even if you are debugging an application, it won’t stop unless you have set the appropriate endpoints in the relevant code points. However, once you set one endpoint, the application will pause immediately upon reaching that endpoint.

While the execution is paused, the UI will become unresponsive. This is because all threads of the application are stopped, included the ones that react to user interaction.

Standard Breakpoints

Standard breakpoints are those that you set specifically in an instruction. In order to do so, you have to click in the line number of a concrete Swift file.
How to Debug iOS Apps in Xcode. Getting To Know The Debugger.

A blue arrow will appear to indicate that you just set a breakpoint. Besides, if you click again on the breakpoint, the arrow will become translucent to indicate that it’s temporary disabled. Clicking on it another time will re-enable the breakpoint.

As we learned in “Your First iOS App“, you can always check the currently enabled breakpoints in the Breakpoint navigator.

Exception Breakpoints

Sometimes the application is crashing, but it’s not easy to determine exactly where. In that situations, it’s useful to setup Exception Breakpoints. An exception breakpoint will stop the execution as soon as an exception occurs anywhere.

If you don’t set an exception breakpoint, your app will crash with little to no indication of what happened. Sometimes you will be taken back to the AppDelegate file. Obviously, that’s not really useful for debugging and fixing the problem.

Thus, it’s always a nice idea setting an exception breakpoint if your application is not behaving correctly. Here’s how to do it:

How to Debug iOS Apps in Xcode. Getting To Know The Debugger.

  • First, Go to the Breakpoint Navigator.
  • Next, click on the “+” symbol at the bottom.
  • Then, choose “Exception breakpoint”.
  • Finally, choose “All” in the “Exception” field to captura all exceptions.

Symbolic Breakpoints

Oftentimes, you need to set breakpoints in parts of code you have no access to. A common scenario is your application crashing when it enters some external library’s code. Another situation where this might happen is a weird crash happening in the code of a standard framework, like UIViewController’s viewDidLoad.

This does not necessarily mean that the crash is not your fault. It indicates that your application is probably accessing this code incorrectly.

In all these scenarios, you might want to add a Symbolic Breakpoint. A symbolic breakpoint allows you to add a breakpoint that will pause the execution whenever the code enters a concrete symbol. Here, “symbol” means the name of a function or method.

In order to add a symbolic breakpoint, you follow the same steps that you followed for the Exception Breakpoint. However, this time you must select “Symbolic Breakpoint” and add a symbol to watch.

The symbols can be expressed either as Objective-C functions:

-[UIViewController viewDidLoad]

Or as C function names:


Debugging Actions

When reaching a breakpoint, execution will pause by default and take you to the breakpoint. However, upon defining the breakpoint, you can specify a set of actions to take place when the breakpoint is reached.

This includes printing some information on the Debug Area or performing some operations, and then continue execution. That’s right, you can define a breakpoint that will not pause, but instead show a message or perform an action, and then continue execution.

To set such functionality, when defining the breakpoint, add an action in the “Action” section, and optionally click on “Automatically continue after evaluating actions”. The action can be many things, from playing a sound to executing a LLDB command.

For example, just for fun, let’s define a breakpoint for “-[UIViewController viewDidLoad]” in any of your applications, like the picture below depicts.

How to Debug iOS Apps in Xcode. Getting To Know The Debugger.

“bt” is an LLDB command that means “backtrace”. It will dump the stack at the point where it’s invoked. In our case, as soon as a View Controller initializes, it will call viewDidLoad, and show a backtrace.

* thread #1, queue = '', stop reason = breakpoint 2.1
 * frame #0: 0x0000000108264654 UIKit`-[UIViewController viewDidLoad]
 frame #1: 0x0000000105fab972 BrokenHelloWorld`ViewController.viewDidLoad(self=0x00007ff815405f90) -> () at ViewController.swift:18
 frame #2: 0x0000000105fab9f2 BrokenHelloWorld`@objc ViewController.viewDidLoad() -> () at ViewController.swift:0
 frame #3: 0x0000000108264cca UIKit`-[UIViewController loadViewIfRequired] + 1235
 frame #16: 0x00000001079e35ff CoreFoundation`__CFRunLoopRun + 911
 frame #17: 0x00000001079e3016 CoreFoundation`CFRunLoopRunSpecific + 406
 frame #18: 0x00000001080bc02f UIKit`-[UIApplication _run] + 468
 frame #19: 0x00000001080c20d4 UIKit`UIApplicationMain + 159
 frame #20: 0x0000000105fad797 BrokenHelloWorld`main at AppDelegate.swift:12
 frame #21: 0x000000010a30f65d libdyld.dylib`start + 1

The Debugger

Xcode includes a pretty awesome debugger. Not only it’s easy to use, but and has many useful features that are more than enough for debugging your projects.

You can access the debugger in the menu by selecting View > Debug Are > View Debug Area. It will probably appear at the bottom of Xcode.

Pro tip: a quick and easy way of displaying the Debug Area is pressing Cmd+Shift+Y.

Let’s have a look at the different parts of the Debug Area:

How to Debug iOS Applications in Xcode. Getting To Know The Debugger.

At the top, you have a bar that controls the debugging process.

  • Its first element shows and hides the Debug Area.
  • The second one disables or enables all breakpoints globally. Currently, you can see that it’s blue, indicating that the endpoints are enabled. You can use this item to easily switch back and forth between debugging and not debugging your application.

Then, the next elements have to do with the interactive debugging process once the execution of the program has paused because it has reached a breakpoint.

  • Continue Program Execution“, the third item allows you to continue the execution normally until it reaches a new breakpoint.
  • Step Over“, the fourth one allows us to skip an instruction completely and jump to the next one. If the instruction we are in is a function, the whole function will be processed and we will land in the next sequential instruction.
  • Next, “Step Into” is similar to “Step Over”, but if the instruction is the call of a function, the execution will enter that function and stop at its first instruction.
  • Finally, “Step out” will continue execution until it leaves the current context, may it be a function, method or code block.

Understanding Debugging Navigation With An Example

Imagine we have the following code sample:

func someFunction() {
   ... // "Step Out" will take you there.

func A() {
   print("Hi there! I am function A")
   print("The final number is \(a)") // "Step Over" will take you here.

func B(_ number: Int) -> Int {
   print("Hi there! I am function B") // "Step Into" will take you here
   var b = 4 + 5
   b = b - number
   return b

Then, let’s say we define a breakpoint just in the call to B(5), run the program and wait until the execution pauses. If you choose “Step Over”, the call to B(5) will be executed, and the resulting value will be assigned to “a”. Immediately after, the execution will stop in the instruction:

print("The final number is \(a)")

However, if you click on “Step Into”, the execution will enter the B() function and stops in the first instruction found there, that is:

print("Hi there! I am function B")

Conversely, if you click on “Step Out”, the execution will process all the instructions in A, including the call to B and the print message. Next, it will exit the function and stop execution immediately after the instruction that called A() in the first place.

As a result, you have lots of options, and a lot of control on the debug process execution.

The whole point, however, is remembering that your goal is focusing on a problem and detecting its location, probably thanks to an exception breakpoint. Then, setting a breakpoint there, and analyzing, step by step, the result of your code’s instructions until you identify the problem. Once you get there and understand the cause of the issue, it’s just a matter of fixing it.

Where To Go Next

In this tutorial series, we explored how to debug iOS Apps in Xcode. This initial episode offers a brief introduction of what’s debugging, why it’s important to master it, and describes you the debugger and how to use it.

In the next episode, we will present a broken app, a Math Quiz game. This application includes a number of bugs -on purpose- to teach you how to debug and fix them.