Today I am going to write about the big advanced debugging feature of LLDB. I am calling it advanced because I myself didn't know about it for a long time. It allows you to add a symbolic breakpoint which will halt the execution at a specific point so that you can backtrack and start investigating into where this method call was triggered.

If the introduction is not making sense, let me explain with the use-case. Suppose somewhere in your code, a method dismissViewController which dismisses the UIViewController gets called. Now there could be hundreds of dismissViewController methods in your codebase. But how do you know which part of the code is actually calling this dismissViewController method? Answer to this question is adding Symbolic Breakpoints.

Once you add a symbolic breakpoint to break at dismissViewController method, the program execution will halt at it and traversing back in the stack trace will let you find the line which is responsible for dismissing the view controller.

Referring to the above screenshot, our program flow has stopped at the call of dismissViewController. If we trace it back, we know that the method viewDidAppear in class Sample is responsible for dismissing this view controller.

Let's take a look at examples of different symbolic breakpoints which could be added during program execution,

  1. Symbolic breakpoint when the value is assigned to the object property

For example, you have a UILabel or UITextView object and you want to know the place where certain properties such as text, numberOfLines or translatesAutoresizingMaskIntoConstraints are assigned to them. You can click on Breakpoint Navigator and click on + symbol at the bottom and select Symbolic Breakpoint as an option.

Now depending on which condition you want to break at, you can add the following values next to `Symbol` field

Property Symbol
numberOfLines -[UILabel setNumberOfLines:]
text -[UILabel setText:]
translatesAutoresizingMaskIntoConstraints -[UIView setTranslatesAutoresizingMaskIntoConstraints:]
textContainerInset -[UITextView setTextContainerInset:]
view (On UIViewController) -[UIViewController setView:]

Now, you can ask - This is fine for putting a break on simple variables. But what about when property names follow names such as isScrollEnabled or isEditable.

Fortunately, it is very similar to what we did earlier. All you need to do it get rid of the prefix is and simply apply the same logic as earlier.

Property Symbol
isScrollEnabled -[UITextView setScrollEnabled:]
isEditable -[UITextView setEditable:]

2.  Symbolic breakpoint when UIViewController is presented

When it comes to stopping the program flow when the arbitrary place in your project prepares to present the view controller, you can do so by adding the following symbol to your symbolic breakpoint

-[UIViewController presentViewController:animated:completion:]

3. Symbolic breakpoint when UIViewController is dismissed

When UIViewController is dismissed, it can be caught by adding the following symbol

-[UIViewController dismissViewControllerAnimated:completion:]

4. Symbolic breakpoint when UIViewController is pushed on the navigation stack

Similar symbol when UIViewController instance is pushed on the navigation controller,

-[UINavigationController pushViewController:animated:]

5. Symbolic breakpoint when you UIViewController is popped from the navigation stack

And when current UIViewController instance is popped from the navigation stack

-[UINavigationController popViewControllerAnimated:]

6. Symbolic breakpoint when UIViewController's lifecycle methods are called

This is a one-off trick to catch execution of any of the lifecycle methods associated with UIViewController such as viewDidLoad, viewDidAppear, viewWillAppear and so on. For example, you can stop the execution when the viewDidLoad method gets called using the following symbol,

-[UIViewController viewDidLoad]

You may apply similar logic to break at other methods.

7. Symbolic breakpoint when the view is added to its superView

Want to detect when the UIView adds another UIView instance as its subView? Simply add the following symbol,

-[UIView addSubview:]

In the end, let's summarize the list of all the symbolic breakpoints that can be created with views and viewControllers to act as a handy list for any debug session,

Method Description Symbol
View Controller presented -[UIViewController presentViewController:animated:completion:] 
View Controller dismissed -[UIViewController dismissViewControllerAnimated:completion:]
View Controller pushed on nav controller -[UINavigationController pushViewController:animated:]
View Controller popped from nav controller -[UINavigationController popViewControllerAnimated:]
viewDidLoad lifecycle method got called -[UIViewController viewDidLoad]
viewDidAppear lifecycle method got called -[UIViewController viewDidAppear:]
Added view as a subview to another view -[UIView addSubview:]

This is all for now. From my experience, I could only create symbolic breakpoints for classes and methods from existing iOS frameworks, and not for my own code. If you know the workaround for it, I would love to hear more.

If you are debugging excessively convoluted code and cannot for sure say where the particular caller is calling from, feel free to use this blog post as a cheat sheet. Any more questions? Feel free to comment, or hit me up on the Twitter!