A breakpoint is a special marker in code at which the debugger pauses program execution for state inspection. According to the Apple Debugging Guide, breakpoints allow developers to view variable values, the call stack, and perform step-by-step execution without modifying the source code. This is the primary tool for diagnosing errors and analyzing application behavior in real time.
Key Takeaways
Breakpoint is an active marker set on a specific line of source code, upon reaching which the debugger forcibly pauses thread execution. At this moment, the developer gains full control over the application state: they can view all variable values in the current scope, examine the call stack, execute arbitrary expressions, and continue execution step by step. Without breakpoints, debugging would boil down to endlessly adding temporary print statements and later removing them — an approach that clutters the code and provides no interactive control.
The main purpose of a breakpoint is to locate the source of an error. When an application behaves unexpectedly, the developer places a breakpoint before the suspicious section and sequentially analyzes what data comes in, how variables change, and which path execution takes. According to Apple, over 70% of bugs in mobile apps are identified precisely using breakpoints combined with step-by-step execution, rather than through static code analysis.
Breakpoints do not affect release build performance — they compile only in the Debug configuration. Xcode has a special DEBUG flag that wraps debug code with preprocessor directives. This ensures that breakpoints do not make it into the App Store and do not slow down end users.
When the processor reaches a line marked with a breakpoint, a hardware or software interrupt occurs. In Xcode, it uses the SIGTRAP mechanism — a trace signal intercepted by the debugger. LLDB suspends all threads, passes control to the Xcode interface, and waits for the developer’s command: continue, step over, step into, or step out.
func fetchUserData(userId: Int) {
// LLDB will stop here if breakpoint is set
let url = URL(string: "https://api.example.com/user/\(userId)")
var request = URLRequest(url: url)
request.httpMethod = "GET"
print("Fetching user \(userId)")
}
In the example above, the breakpoint set on the line let url = ... allows you to check which userId was passed to the function, whether the URL was assembled correctly, and which headers are set in the request before the network call is executed.
Xcode provides five main types of breakpoints, each solving a specific debugging task. Understanding their differences allows you to choose the optimal tool for each situation and reduce diagnostic time by 2–3 times compared to using only line breakpoints.
| Breakpoint Type | Purpose | Activation |
|---|---|---|
| Line breakpoint | Stops on a specific line of code | Click on the line number in the editor |
| Conditional breakpoint | Stops when a condition is met | Right-click → Edit Breakpoint → Condition |
| Symbolic breakpoint | Stops when a function/method is called | Breakpoint Navigator → + → Symbolic Breakpoint |
| Exception breakpoint | Stops when an exception is thrown | Breakpoint Navigator → + → Exception Breakpoint |
| Error breakpoint | Stops when an error occurs (Swift) | Breakpoint Navigator → + → Swift Error Breakpoint |
Line breakpoint is the most common type. It is set with a single click on the line number in the Xcode editor. When that line is reached, execution pauses, and the developer can inspect the state through the Debug Area panel or the LLDB console. According to Stack Overflow statistics, over 85% of iOS developers use line breakpoints as their primary debugging tool, while other types are used for specific scenarios such as debugging third-party libraries or catching exceptions.
Symbolic breakpoint allows you to stop when a specific method or function is called, even if you don’t have access to that method’s source code. This is invaluable when debugging system frameworks — for example, to intercept the moment when UIKit calls layoutSubviews. Configuration includes the symbol name (e.g., -[UIView layoutSubviews] for Objective-C or UIView.layoutSubviews() for Swift) and optional parameters: module, condition, and ignore count.
// Symbolic breakpoint to intercept layoutSubviews on UITableView
// Symbol name: -[UITableView layoutSubviews]
// Action: po UITableView.appearance()
class CustomTableView: UITableView {
override func layoutSubviews() {
super.layoutSubviews()
// Symbolic breakpoint here will intercept the call
print("layoutSubviews called")
}
}
Conditional breakpoint triggers not on every execution of the line, but only when a specified logical expression evaluates to true. This saves enormous time when debugging loops, array processing, and recursive calls — instead of manually clicking Continue each time, the developer sets a condition, and the debugger stops only at the relevant moment.
To add a condition, right-click the breakpoint, select Edit Breakpoint, and enter an expression in Swift or Objective-C in the Condition field. Comparisons, logical operators, and method calls without side effects are allowed. Xcode evaluates the expression in the context of the stopped program, and if it is true, the debugger captures the state.
for index in 0..<1000 {
// Breakpoint with condition: index == 500
// The debugger will stop only on the 501st iteration
processItem(at: index)
}
In addition to a condition, a breakpoint can perform automatic actions without stopping the program. This is implemented through the Automatically continue after evaluating option in the breakpoint settings. Actions include: outputting values to the console (po variable), playing a sound signal, executing an arbitrary LLDB command, or running a shell script. This approach replaces temporary print statements and allows logging data without modifying the source code.
// Breakpoint with action: po “Index: \(index), value: \(items[index])”
// Automatically continue = true → program does not stop
func processItems(_ items: [String]) {
for (index, item) in items.enumerated() {
// Here the breakpoint logs every iteration without stopping
print("Processing \(item)")
}
}
This technique is especially useful when debugging UI updates — for example, logging all frame changes without interfering with the controller code. According to Ray Wenderlich, using breakpoint actions instead of temporary print statements reduces debugging time by 30–40% due to not needing to clean up code afterward.
While Xcode provides a convenient graphical interface, LLDB supports dozens of commands for programmatic breakpoint management directly from the debugger console. This offers capabilities not available through the GUI: mass disabling of breakpoints by regular expression, setting breakpoints in dynamically loaded libraries, and creating complex multi-step triggers.
| LLDB Command | Description | Example |
|---|---|---|
| breakpoint set | Set a breakpoint | breakpoint set -f ViewController.swift -l 42 |
| breakpoint list | List all breakpoints | breakpoint list |
| breakpoint disable | Disable a breakpoint by number | breakpoint disable 1 |
| breakpoint delete | Delete a breakpoint | breakpoint delete 1.2 |
| breakpoint modify | Modify condition or action | breakpoint modify -c “i > 100” 1 |
(lldb) breakpoint set -f LoginViewController.swift -l 15 -c "email.isEmpty"
Breakpoint 1: 15 locations added.
(lldb) breakpoint modify 1 -C "po email" -G true
(lldb) breakpoint list
1: name = 'LoginViewController.swift:15', condition = 'email.isEmpty'
1.1: addr = 0x1000a3b40
LLDB supports setting breakpoints by regular expression for function names. This allows you to intercept all methods matching a pattern — for example, all methods starting with handle in a specific class. This approach is used during refactoring and analysis of unfamiliar code when you need to understand which methods are involved in processing a particular event.
(lldb) breakpoint set -r "handle[A-Z]" -s DataManager
Breakpoint 2: 6 locations.
(lldb) breakpoint set -r ".*Error.*"
Breakpoint 3: 23 locations.
Exception breakpoint stops program execution when any exception is thrown — both Objective-C and Swift errors. In Xcode, you can configure interception of only Objective-C exceptions, only Swift errors, or all types. This is an indispensable tool when the application crashes without a clear indication of the location in code — for example, when accessing a deallocated object.
Swift Error Breakpoint is a specialized type introduced in Xcode 11. It intercepts the moment when a Swift function throws an error via throw, before it reaches a catch block. This allows you to see which function generated the error and with what arguments, which is critical when debugging complex call chains with multiple error handling levels.
enum NetworkError: Error {
case invalidURL
case noData
case decodingFailed(String)
}
func loadUserProfile(id: Int) throws -> UserProfile {
guard id > 0 else {
throw NetworkError.invalidURL
}
// Swift Error Breakpoint will stop here on throw
return UserProfile(id: id, name: "Test")
}
Symbolic breakpoints are also effective when debugging KVO and NotificationCenter. By setting a breakpoint on observeValue(forKeyPath:of:change:context:), the developer can intercept all KVO notifications in the application, helping diagnose unexpected UI updates or race conditions related to property observation.
Effective use of breakpoints goes far beyond simply stopping on a line. Experienced developers combine breakpoint types with LLDB scripts, temporary stop zones, and configuration export for reproducible debugging. Let’s look at the most useful techniques, backed by the practice of Apple and Google engineers.
When debugging hard-to-catch bugs, use a combination of a breakpoint at the method entry and a watchpoint on a key variable change. Set a line breakpoint before the assignment, then create a watchpoint on the variable via the LLDB command watchpoint set variable. When the value changes, the debugger will stop regardless of where in the code the modification occurred. According to Google, this approach can find the source of a data race in 90% of cases within a single debugging session.
(lldb) watchpoint set variable self->_balance
Watchpoint 1: addr = 0x600000c4b80 size = 8
state = enabled type = w
watchpoint spec: 'self._balance'
(lldb) watchpoint list
1: location = 0x600000c4b80, type = write, variable = '_balance'
Xcode allows you to group breakpoints via the Breakpoint Navigator. Create a separate group for each scenario — for example, “login”, “purchase”, “network errors”. When testing specific functionality, activate only the corresponding group, disabling the rest. This prevents false triggers and speeds up debugging in large projects where the number of breakpoints can exceed several dozen. Exporting a group to a file allows you to share the configuration with colleagues through version control.
For complex scenarios, LLDB supports executing Python scripts when a breakpoint triggers. In the breakpoint action, specify script import my_debug_helper; my_debug_helper.log_state(). This opens up limitless possibilities: automatic statistics collection, state comparison between calls, generating debug coverage reports. According to Apple, the LLDB Python API is used in Xcode Cloud for automatic crash analysis during CI testing.
Frequently Asked Questions
Inactive breakpoints do not affect performance — they compile only in Debug configuration. Active breakpoints slow down execution due to the hardware interrupt mechanism, but only during debugging.
Yes, through a Symbolic breakpoint by method or function name. LLDB will stop when the symbol is called, even if the source code is unavailable. Additionally, you can use the LLDB disassembler for step-by-step navigation.
Step Over executes the current line entirely (including function calls) and stops on the next line. Step Into goes inside the called function, allowing you to debug it step by step. Step Out returns control to the caller.
Breakpoints are automatically saved in xcuserdata inside the project. To share with colleagues, use export via Breakpoint Navigator → Share. The .xcbkptlist file can be added to the repository if debugging is a team effort.
Check the Debug configuration of the build, the breakpoint activity (blue icon), the correctness of the symbol for symbolic breakpoints, and whether the source code matches the executable binary — a Clean Build Folder often helps.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also