Earlier in this course, we briefly explored the types of breakpoints you can use in Xcode. In the previous video, we focused on file and line breakpoints. This video zooms in on symbolic breakpoints.
Symbolic Breakpoints
Remember that a file and line breakpoint is associated with a specific location in the codebase hence the name. A symbolic breakpoint is different. As the name implies, a symbolic breakpoint is linked to a symbol, such as a method or function name. This type of breakpoint can be helpful for debugging problems that involve code you don't have direct access to. Let me explain what that means.
Symbolic breakpoints are often used in scenarios in which your code interacts with a library or framework, including Apple's libraries and frameworks. Because you don't have access to the source code of the library or framework, it isn't possible to set a file and line breakpoint. Let me show you how symbolic breakpoints work and why they are useful.
Example 1
Let's revisit Cloudy. Add a file and line breakpoint to RootViewController.swift on line 158, a line of the fetchWeatherData()
method. If we run the app, the debugger pauses its execution on line 158 of RootViewController.swift. That should be familiar by now.
Let's replace the file and line breakpoint with a symbolic breakpoint. Disable the file and line breakpoint. Click the + button in the bottom left of the Breakpoint Navigator and choose Symbolic Breakpoint.
A symbolic breakpoint is linked to a symbol, such as a method or function name, and Xcode asks us for the symbol the debugger needs to break on. Don't let yourself be thrown off by the term symbol. A symbol is nothing more than an identifier that uniquely identifies a method or function. It is a bit more complex under the hood, but that is what you need to know to work with symbolic breakpoints.
If we want to break on the fetchWeatherData()
method, we enter the name of the method as the symbol of the breakpoint. Notice that we don't append a pair of parentheses to the symbol. The debugger is only interested in the name of the method or function. We leave the other fields empty for now.
Run the app to see the result. The debugger pauses the app's process on line 152 in RootViewController.swift. The app's process is paused every time the fetchWeatherData()
method is invoked.
Example 2
In the first example, we replaced a file and line breakpoint with a symbolic breakpoint. While this can be useful at times, symbolic breakpoints are mostly used to break on methods or functions you don't have direct access to. Let's see how that works with another example.
Open Main.storyboard and navigate to the Day View Controller scene. Add a view to the view controller's view. Center it horizontally and vertically in its superview. Set the width and the height of the view to 100 points. Add one more constraint to set the width to 200 points. The last constraint we added results in a conflict for obvious reasons.
Run the app and inspect the output in the console. Xcode warns us that Auto Layout isn't able to satisfy the constraints we defined in the storyboard. To catch this in the debugger, Xcode suggests to add a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints
. Let's do that.
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x600002100410 UIView:0x107e08110.width >= 200 (active)>",
"<NSLayoutConstraint:0x6000021003c0 UIView:0x107e08110.width == 100 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600002100410 UIView:0x107e08110.width >= 200 (active)>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
Disable the symbolic breakpoint we defined earlier and add a new symbolic breakpoint. Set the symbol of the breakpoint to UIViewAlertForUnsatisfiableConstraints
.
Run the app one more time. The debugger breaks the app's process the moment the symbolic breakpoint is hit. That is a good start, but we need more information to debug the issue. We have a few options.
Later in this course, we discuss debugging the view hierarchy in more detail. Another simpler option is to use the output in the console. The problem is that the console can become cluttered over time and you don't always notice the warnings Xcode outputs in the console.
For that reason, I tend to add an action to the symbolic breakpoint. We covered that earlier in this course. Every time the breakpoint is hit, we play a sound to warn us about the issue. We also check the checkbox at the bottom, Automatically continue after evaluating actions, to resume the app's process after playing the sound.
What's Next?
Each developer builds up its own collection of tricks and techniques to debug issues. There is no one solution to debug a problem. Symbolic breakpoints are very powerful and I find that they are underused. It is true that symbolic breakpoints are more advanced and that is what scares many developers. I hope this video has made symbolic breakpoints less daunting.
In the next video, we look at the Swift error and exception breakpoints. These breakpoints are helpful to debug problems that involve errors or exceptions.