Xcode ships with a powerful debugger. It's power comes from LLDB, the debugger of the LLVM project. In this tutorial, I want to share a tip few developers know about. Although I have been using Xcode for more than a decade, I only discovered it recently.

Inspecting Global Variables in Xcode's Debugger

For this tutorial, we use the project we built in Mastering MVVM with SwiftUI, a weather app named Thunderstorm.

The project uses Swinject for dependency injection. The app defines a shared dependency injection container that can be accessed through the static shared property. Don't worry if you are unfamiliar with Swinject or dependency injection. You only need to know that the Container class exposes a singleton we can access through its static shared property. In ThunderstormApp.swift, we register dependencies with the shared container in the registerServices() method.

import SwiftUI
import Swinject

@main
struct ThunderstormApp: App {

    // MARK: - Initialization

    init() {
        registerServices()
    }
    
    // MARK: - App

    var body: some Scene {
        WindowGroup {
            LocationsView(
                viewModel: .init(
                    store: Container.store,
                    weatherService: WeatherClient()
                )
            )
        }
    }

    // MARK: - Helper Methods

    private func registerServices() {
        Container.shared.register(Store.self) { _ in
            UserDefaults.standard
        }
    }

}

Suspending the App with a Breakpoint

We add a breakpoint to the start() method of the LocationsViewModel class to suspend the app's process soon after launch. Let's build and run the app to see the result.

Suspending the App with a Breakpoint

To open the variables view, we click the button in the bottom right. The variables view lists self, the view model, and the weather service, but there is no trace of the shared container.

Suspending the App with a Breakpoint

Exploring the Variables View

Xcode by default lists variables it thinks are useful for you and it is usually correct. The problem is that we don't see the shared container in the list of variables. You can override the default behavior by clicking the picker in the bottom left. The options you have are Auto, the default option, Local Variables, and All Variables, Registers, Globals and Statics.

Exploring the Variables View

Let's select All Variables, Registers, Globals and Statics and see what happens. We still don't see the shared container.

Exploring the Variables View

Let's change the selection back to Auto for now.

Adding Expressions

We can make the shared container show up through an expression. Right-click the variables view and choose Add Expression... from the contextual menu.

How to Inspect Global Variables in Xcode Debugger

In the dialog that appears, we enter the expression to access the shared container, Container.shared. What follows is pretty impressive.

How to Inspect Global Variables in Xcode Debugger

The variables view now lists the shared container. We can query it just like the local variables the variables view lists.

How to Inspect Global Variables in Xcode Debugger

The cherry on the cake is that Xcode remembers the expressions we enter. Let's stop the app's process and trigger another build. The debugger hits the breakpoint and the variables view is populated with the local variables and the shared container. That's quite nice. Right?

If you want to clean up the variables view, then right-click the result of an expression and choose Delete Expression from the contextual menu. You can also edit an expression by right-clicking an expression and choosing Edit Expression... from the contextual menu.

What's Next?

Xcode is fairly straightforward to use, but it takes years before you truly master it. Even after more than a decade, I continue to find little gems like the one we covered in this tutorial. The journey never ends!