Xcode symbolic breakpoints - Break at method call
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,
- 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!