Changing runtime state with LLDB while debugging iOS apps
Learn how to use LLDB's expr command to modify variables at runtime.
30 Mar 2026 · 5 min read
When developing an iOS app, we often need to bring the app into a very specific state, for example when reproducing bugs or testing edge cases.
LLDB provides a powerful way to achieve that: we can modify values at runtime using the expression command, without touching our source code or restarting the app.
Let's take a look at how this works.

Modifying values from the console
When our app pauses at a breakpoint, we can use Xcode's console to change a variable to a state we need.
Let's imagine, we are trying to fix a bug that only is reproducable for birds that have a critically endangered conservation state. When a breakpoint hits the relevant line, let's at first print the bird's conservationStatus in Xcode's console:
(lldb) po bird.conservationStatus.title"endangered"
Since we'd like to test the app with a different conservationStatus, we can use the expr (or its shorthand p) command to change it:
(lldb) p bird.conservationStatus = .cr
When printing the conservationStatus again, we get:
(lldb) po bird.conservationStatus.title"critically endangered"
From here, we can continue execution and observe how the app behaves under this modified state.
This is especially useful when a bug only appears under rare conditions that are otherwise difficult to reproduce.
When this approach is useful
In practice, this is not the only way to approach these situations. In many cases, we might simply hardcode a value directly in the code to reach the desired state and avoid committing that change. This approach is often more explicit and easier to reason about, especially when working with Swift's type system.
Modifying state with LLDB becomes useful in situations where reproducing a specific state is otherwise time-consuming or difficult.
For example, we might already be several screens deep in a navigation flow and want to test a specific edge case. Instead of restarting the app and navigating back to the same point, we can modify the state directly at the breakpoint:
expr result = .error
This approach is also helpful when experimenting with different values during debugging. Instead of repeatedly changing code and rebuilding, we can quickly explore different scenarios:
expr config.isEnabled = false
Limitations
While this technique is powerful, there are a few important limitations:
- Constants (let) cannot be modified: attempting to assign a new value will result in an error.
- Value types may behave unexpectedly: when working with structs, we are mutating a copy in some contexts. The change may not propagate as expected.
- SwiftUI state isn't always mutable this way: properties like @State may not respond reliably to LLDB mutations.
Automating changes with breakpoint actions
When reproducing a bug, we sometimes want a variable to always have a certain value without typing the command every time in the console.
In this case, we can use a breakpoint action.
- Set a breakpoint at the relevant location
- Right-click the breakpoint and choose Edit Breakpoint
- Add an action of type Debugger Command
- Enter the command:
expr bird.conservationStatus = .cr
- Enable Automatically continue after evaluating actions.
Now, every time the breakpoint is hit, LLDB applies the change and continues execution immediately. This allows us to consistently reproduce a specific scenario without interrupting the flow.



Newsletter
Like to support my work?
Say hi
Related tags
Articles with related topics
Latest articles and tips



