What kinds of breakpoints are there in Xcode and LLDB, and how do conditions, actions, symbolic and exception breakpoints and watchpoints help?
Predict first
A conditional line breakpoint and a symbolic breakpoint on add are set without running. What does LLDB report for each?
// === main.swift ===
var total = 0
func add(_ n: Int) {
total += n
}
for i in 1...5 {
add(i)
}
print("total", total)
- Breakpoint 1 resolves to one location; Breakpoint 2 matches several functions
- Both resolve to exactly one location
- Neither resolves until the program runs
Mental model. A normal breakpoint is a guard who stops every passer-by. A conditional one stops only the person in the red coat, and a logging one writes down each name and waves everyone through.
A line breakpoint stops when execution reaches a line; the useful part is what you add to it. A condition (n == 3) stops only when an expression is true, an ignore count skips the first N hits, and an action runs without stopping: log a message with expressions in it, run a debugger command or play a sound, then automatically continue. A breakpoint with a log action and auto-continue is a temporary print that needs no rebuild and nothing to remove, so it is the right tool for “what are the values each time this runs”. In LLDB the same options are flags on breakpoint set (-c condition, -i ignore count, -G true auto-continue), and breakpoint list shows hit counts and the resolved locations.
A symbolic breakpoint stops when any function with that name runs, with no source line needed: useful for framework code (UIViewAlertForUnsatisfiableConstraints stops when Auto Layout breaks a constraint, so you can read the stack that caused it), but a name is matched everywhere, so add matches your function and several in the Swift runtime, as the check below shows; qualify it by module or file. An exception breakpoint stops at the moment an Objective-C exception is raised or a Swift error is thrown (breakpoint set -E swift), which gives the real call stack instead of the later crash in the run loop. A watchpoint (watchpoint set variable total, or “Watch” on a variable in Xcode) stops when a value changes, found with hardware support, so only a small number can be active at once; it answers “who changes this?” when you cannot find the writer. Remember that stopping changes timing, so a race can vanish under the debugger; use logging breakpoints or os_log for those.
A line breakpoint resolves to its line; a bare name matches every function called that, including ones in the runtime libraries.
Common traps
- A symbolic breakpoint on a common name. It matches many functions in many libraries and stops constantly; add the module or use a file and line.
- Stepping through a loop to reach the bad iteration. Put a condition or ignore count on the breakpoint instead.
They might follow up with
- How do you see why a constraint breaks? A symbolic breakpoint on
UIViewAlertForUnsatisfiableConstraints, then read the call stack and the console message. - What does a watchpoint need? A variable with a stable address, and hardware support, so only a few can be active at once.
Related questions
- 23.1.2 How do expressions and printing work in LLDB (p, po, v), and how do you customise it with summaries, aliases…
- 23.2.1 How do you debug layout and views with the view debugger, and how do you inspect what your app really sends…
- 23.4.1 How does the unified logging system work: Logger, levels, subsystems and categories, privacy, and how do you…
- 9.1.1 How does Auto Layout work, and what are intrinsic size, content hugging, compression resistance, priorities…
How do expressions and printing work in LLDB (p, po, v), and how do… →