A lightweight, zero-cost debugging utility for Swift projects that automatically strips debug statements from release builds.
## Overview
The `DebugHelpers.swift` file provides debug logging macros that are completely removed during release builds, ensuring zero performance impact in production.
## Features
– **Zero runtime cost in release builds** – All debug code is stripped at compile time
– **Simple API** – Drop-in replacement for `print()`
– **File and line tracking** – Optional detailed logging with source location
– **Debug assertions** – Catch issues early in development
## Usage
### Basic Debug Logging
Replace `print()` with `DLOG()`:
“`swift
// Old way (appears in release builds):
print(“User logged in:”, username)
// New way (stripped from release builds):
DLOG(“User logged in:”, username)
“`
### Debug Logging with Source Location
When you need to know exactly where a log came from:
“`swift
DLOG_TRACE(“Error occurred”)
// Output: [ViewController.swift:42] Error occurred
“`
### Debug Assertions
Catch programming errors during development:
“`swift
DASSERT(user.age > 0, “User age must be positive”)
// Only fires in DEBUG builds
// In release: completely removed
“`
## API Reference
### `DLOG(_ items: Any…, separator: String = ” “, terminator: String = “\n”)`
Basic debug print that works exactly like Swift’s `print()` but only in DEBUG builds.
**Parameters:**
– `items` – Values to print
– `separator` – String to separate values (default: ” “)
– `terminator` – String to end the line (default: “\n”)
**Example:**
“`swift
DLOG(“Processing”, itemCount, “items”)
“`
### `DLOG_TRACE(_ items: Any…, file: String = #file, line: Int = #line)`
Debug print with file and line number information.
**Parameters:**
– `items` – Values to print
– `file` – Source file (automatically captured)
– `line` – Line number (automatically captured)
**Example:**
“`swift
DLOG_TRACE(“Unexpected state”)
// Output: [MyView.swift:127] Unexpected state
“`
### `DASSERT(_ condition: Bool, _ message: String = “”, file: String = #file, line: Int = #line)`
Debug-only assertion that crashes the app if condition is false.
**Parameters:**
– `condition` – Boolean condition to check
– `message` – Description of the assertion
– `file` – Source file (automatically captured)
– `line` – Line number (automatically captured)
**Example:**
“`swift
DASSERT(array.count > 0, “Array should not be empty”)
“`
## How It Works
The macros use Swift’s `#if DEBUG` preprocessor directive:
“`swift
func DLOG(_ items: Any…) {
#if DEBUG
print(items)
#endif
}
“`
When you build for release (without the DEBUG flag), the compiler completely removes all code inside `#if DEBUG` blocks. This means:
– No runtime overhead
– No string allocations
– No function calls
– Zero bytes in the binary
## Setting Up in New Projects
### Option 1: File Template
1. Create the template directory:
“`bash
mkdir -p ~/Library/Developer/Xcode/Templates/File\ Templates/Custom/Debug\ Helper.xctemplate
“`
2. Copy the template files to that directory
3. Restart Xcode
4. New file → Custom → Debug Helper
### Option 2: Code Snippet
1. In Xcode, select the `DebugHelpers.swift` code
2. Right-click → Create Code Snippet
3. Set completion shortcut: `debughelpers`
4. In any project, type `debughelpers` + Enter
### Option 3: Manual Copy
Simply drag `DebugHelpers.swift` into your new project.
## Best Practices
### DO:
– Use `DLOG()` for temporary debugging during development
– Use `DLOG_TRACE()` when you need to track execution flow
– Use `DASSERT()` to catch programming errors early
– Remove debug statements once issues are resolved
### DON’T:
– Don’t use for production logging (use OSLog or a logging framework)
– Don’t log sensitive information (even in debug builds)
– Don’t use as a permanent logging solution
## Benefits Over `print()`
| Feature | `print()` | `DLOG()` |
|———|———–|———-|
| Works in DEBUG | ✅ | ✅ |
| Works in RELEASE | ✅ | ❌ (intentional) |
| Runtime cost in release | ⚠️ Yes | ✅ Zero |
| Binary size impact | ⚠️ Increases | ✅ None |
| String evaluation cost | ⚠️ Always | ✅ DEBUG only |
## Migration Guide
### Finding print statements to replace:
“`bash
# Find all print() calls in Swift files
grep -r “print(” –include=”*.swift” .
“`
### Replace with DLOG:
“`swift
// Before:
print(“Loading data…”)
print(“Items:”, items.count)
print(“Error:”, error.localizedDescription)
// After:
DLOG(“Loading data…”)
DLOG(“Items:”, items.count)
DLOG(“Error:”, error.localizedDescription)
“`
## Advanced Usage
### Custom Debug Helpers
You can extend the pattern for specific needs:
“`swift
#if DEBUG
func DLOG_NETWORK(_ url: URL, _ response: HTTPURLResponse?) {
print(“🌐 Network: \(url)”)
if let status = response?.statusCode {
print(” Status: \(status)”)
}
}
#else
func DLOG_NETWORK(_ url: URL, _ response: HTTPURLResponse?) {}
#endif
“`
### Conditional Compilation Flags
Check your build configuration:
– Xcode → Target → Build Settings → Swift Compiler – Custom Flags
– DEBUG should be in “Other Swift Flags” for Debug configuration: `-D DEBUG`
## Troubleshooting
### “DLOG is showing in release builds”
Check your build configuration:
1. Select your target
2. Build Settings → Swift Compiler – Custom Flags
3. Debug configuration should have `-D DEBUG`
4. Release configuration should NOT have `-D DEBUG`
### “Cannot find DLOG in scope”
Make sure `DebugHelpers.swift` is included in your target’s compile sources:
1. Select the file in project navigator
2. File Inspector → Target Membership
3. Check your app target
## Performance Notes
In DEBUG builds, these macros have the same performance as `print()`.
In RELEASE builds:
– **Zero CPU cost** – Code doesn’t exist
– **Zero memory cost** – Strings not allocated
– **Zero binary size** – Completely stripped
Example binary size comparison on a real project:
– With 100 `print()` statements: +8KB
– With 100 `DLOG()` statements: +0KB i