Xcode
Debugging
Object Printing
Nil Error
Software Development

Xcode debugger doesn't print objects and shows nil, when they aren't

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

When Xcode shows an object as nil even though the app is clearly using it, the debugger is often lying by omission rather than revealing the true runtime state. The usual causes are compiler optimization, the current stack frame, expression evaluation limits, or an object that exists but cannot be materialized the way LLDB expects. The fix is to treat the debugger output as evidence, not as an infallible source of truth.

Start With the Build Configuration

The first thing to check is whether you are debugging an optimized build. Under optimization, Swift and Objective-C variables can be moved, inlined, elided, or kept in registers in ways that no longer map cleanly back to source-level names.

For local debugging, use the Debug configuration with optimizations disabled.

text
Swift Compiler - Code Generation -> Optimization Level = None (-Onone)

If you are debugging a Release-like configuration, LLDB may show stale values, <optimized out>, or nil for variables that still exist in the generated machine code.

Use the Right LLDB Command

po, p, and frame variable do different things.

  • 'po prints an Objective-C or Swift object description.'
  • 'p evaluates an expression.'
  • 'frame variable dumps variables from the current stack frame.'

Try more than one:

lldb
frame variable myObject
p myObject
po myObject

If frame variable shows something useful but po fails, the issue may be expression evaluation rather than object lifetime.

If the value exists only in another frame, switch frames before inspecting it:

lldb
bt
frame select 2
frame variable

A variable can be real and non-nil in one frame while being out of scope in the frame you are currently inspecting.

Watch for Weak References and Lazy State

Sometimes the debugger is not wrong. A weak property may genuinely be nil by the time you stop, even if the object existed earlier.

swift
final class Owner {
    weak var delegate: NSObjectProtocol?
}

Likewise, lazy or computed properties may not have been evaluated yet. If you inspect them in LLDB before the program accesses them normally, the debugger may show a confusing state or even trigger code when you print them.

A safer pattern is to confirm the object through normal code paths first, then inspect it after it has been assigned and used.

Expression Evaluation Can Fail Independently

LLDB sometimes cannot evaluate a Swift expression even though the program itself is fine. Bridging, generic types, protocol existentials, and heavily optimized code all make expression evaluation less reliable.

A practical workaround is to bind the object to a simpler local variable before the breakpoint.

swift
let debugUser = user
print(debugUser.name)

Then inspect debugUser at the breakpoint. Simple locals are much easier for the debugger to display consistently than nested expressions such as viewModel.currentSession?.user.profile.

Verify With Runtime Logging When Needed

If the debugger output conflicts with what the app is doing, add a temporary runtime check.

swift
1if let user = user {
2    print("user exists:", user)
3} else {
4    print("user is nil")
5}

That is not a substitute for debugging, but it is a good way to separate a debugger-display problem from a real logic bug.

In difficult cases, compare all three sources:

  • runtime logging
  • 'frame variable'
  • 'po or p in LLDB'

If only LLDB claims the object is nil, optimization or expression evaluation is the likely culprit.

Common Pitfalls

  • Debugging optimized code and expecting perfect source-level variable visibility.
  • Using only po and assuming it is the most accurate view of program state.
  • Inspecting the wrong stack frame.
  • Forgetting that weak references may legitimately become nil.
  • Printing complex chained expressions when a simple local variable would be easier for LLDB to inspect.

Summary

  • Xcode can show misleading nil values when optimization or LLDB evaluation gets in the way.
  • Use Debug builds with -Onone for reliable inspection.
  • Compare frame variable, p, and po instead of trusting one command.
  • Confirm you are in the correct stack frame and that the variable is still in scope.
  • When in doubt, verify the value with temporary runtime logging.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.