Crafting Efficient Debug Menus in Swift with Spices: A Developer’s Guide

As an iOS developer, have you ever felt bogged down by the constant need to adjust configurations during development and testing? Switching API environments, toggling logs, or experimenting with feature flags can quickly become a repetitive and error-prone chore. Fortunately, there’s a handy solution: Spices, an open-source Swift library that makes creating debug menus a breeze. With Spices, you get auto-generated, native UI for your debug settings and effortless integration through Swift Package Manager (SPM). In this blog, I’ll guide you through using Spices from a developer’s perspective, complete with practical examples and tips to level up your debugging game.
What is Spices?
Spices is a lightweight, open-source tool designed to help iOS developers whip up debug menus in no time. With its straightforward API and clever property wrappers, you define your debug settings, and Spices takes care of generating the UI automatically. By default, all settings are saved in UserDefaults
, ensuring they persist across app launches. Whether you’re juggling API environments, toggling logs, or testing mock data, Spices simplifies your workflow like a pro.
In this guide, I’ll walk you through the entire process—from integrating Spices into your project to putting it to work in real-world scenarios.
Getting Started: Adding Spices to Your Project
To kick things off, you’ll need to add Spices to your Swift project using Swift Package Manager (SPM). Here’s how to do it:
- Open your
Package.swift
file or head to Xcode’s File > Add Packages menu. - Add the Spices GitHub repository as a dependency:
dependencies: [
.package(url: "https://github.com/shapehq/spices", from: "4.0.0")
]
- Import the Spices module in your code:
import Spices
Pro Tip: The version (
4.0.0
) here is just an example. Check the Spices GitHub page for the latest release to ensure you’re getting the newest features and bug fixes.
Once that’s done, Spices is ready to roll in your project, and you can start defining your debug settings.
Defining Your Debug Settings
The core of Spices lies in the SpiceStore
protocol. You’ll create a class or struct that conforms to this protocol and use the @Spice
property wrapper to flag the settings you want in your debug menu. Spices then autogenerates the UI based on the property types—no manual UI coding required!
Here’s a real-world example:
enum Environment: String, CaseIterable {
case development, staging, production
}
class DebugSettings: SpiceStore {
@Spice(key: "environment") var environment: Environment = .production
@Spice(key: "logging") var loggingEnabled: Bool = false
@Spice(key: "mockData") var useMockData: Bool = false
}
Breaking It Down
environment
: An enum for picking API environments—Spices turns this into a picker UI.loggingEnabled
: A boolean for toggling logs, displayed as a switch.useMockData
: Another boolean to enable mock data, also shown as a switch.
Why Spices Shines
Spices picks the perfect UI control based on your property type:
- Bool → Toggle switch
- Enum → Picker
- String → Text field
- Int/Double → Slider or number input
This automation has saved me tons of time when I need to tweak settings on the fly during development.
Displaying the Debug Menu in Your App
With your settings defined, it’s time to bring the debug menu into your app’s UI. A common approach is to trigger it with a button. Here’s how you can do it in SwiftUI:
struct ContentView: View {
@State var showMenu = false
var body: some View {
VStack {
Button("Show Debug Menu") {
showMenu = true
}
}
.fullScreenCover(isPresented: $showMenu) {
SpicesMenu(store: DebugSettings())
}
}
}
Tap the button, and voilà—a full-screen debug menu pops up with all your DebugSettings
options. The presentation style might differ slightly depending on the Spices version, so double-check the official docs for the latest API specifics.
Putting Debug Settings to Work
Setting up the menu is just the start. The real magic happens when you use these settings to dynamically adjust your app’s behavior. Here are some practical examples:
1. Switching API Environments
func fetchData() {
let baseURL: String
switch DebugSettings().environment {
case .development:
baseURL = "https://dev.example.com"
case .staging:
baseURL = "https://staging.example.com"
case .production:
baseURL = "https://www.example.com"
}
let url = URL(string: baseURL + "/data")!
// Make your network request here
}
2. Toggling Log Output
func performOperation() {
if DebugSettings().loggingEnabled {
print("Starting operation...")
}
// Run the operation
}
3. Testing with Mock Data
func loadData() -> [String] {
if DebugSettings().useMockData {
return ["Mock Item 1", "Mock Item 2"]
} else {
// Fetch real data from the network
return []
}
}
These snippets show how Spices lets you tweak app behavior without touching the codebase—a lifesaver during debugging and testing.
Best Practices and Tips
Spices is a fantastic tool, but here are some best practices to keep in mind:
-
Keep It Dev-Only
Spices is built for debugging, not production. Use build configurations like
#if DEBUG
to hide the menu in release builds:
#if DEBUG
Button("Show Debug Menu") { showMenu = true }
#endif
-
Mind Persistence
Settings stick around in
UserDefaults
, which is great for convenience but not for sensitive data like API keys. -
Watch Performance
Spices uses reflection for UI generation, which is fine for debugging but might warrant a quick performance check in edge cases.
-
Avoid Key Clashes
The
key
in@Spice
must be unique to prevent settings from overwriting each other.
Bonus: SwiftUI Integration
Here’s a neat surprise: Spices plays beautifully with SwiftUI’s @AppStorage
. Since settings are stored in UserDefaults
, you can bind them directly in your views:
struct DebugView: View {
@AppStorage("environment") var environment: Environment = .production
var body: some View {
Text("Current Environment: \(environment.rawValue)")
}
}
This synergy makes Spices even more versatile for SwiftUI projects.
Wrapping Up
Spices is a straightforward yet powerful library that lets me add robust debug menus to my Swift projects in minutes. From switching environments to testing features, it’s boosted my productivity big time. If you’re ready to simplify your debugging process, I can’t recommend Spices enough—give it a spin!
Head over to the Spices GitHub page for the latest updates. Loved it? Drop a star on the repo to support the community!
I hope this guide sparks some inspiration for your next project. Got thoughts or experiences to share? Drop them in the comments below—I’d love to hear from you!