What is Hot Reloading?
Hot reloading lets you modify Swift files and see changes appear in your running app immediately—without recompiling or restarting. When you save a file, InjectionIII:- Recompiles only the changed file
- Injects the new code into the running app
- Triggers SwiftUI views to re-render
Hot reloading is Debug-only. All InjectionIII code, bundle loads, and linker flags are completely disabled in Release builds.
Setup Instructions
Install InjectionIII
Download and install InjectionIII from the Mac App Store.
InjectionIII is a free, open-source tool maintained by John Holdsworth.
Launch InjectionIII
- Open the InjectionIII app
- Click the InjectionIII menu bar icon
- Select Open Project
- Navigate to and select your
browserfolder (the repository root)
Build and Run in Debug Mode
In Xcode:
- Ensure the Debug scheme is selected (not Release)
- Press ⌘R to build and run the app
- Watch for a green status indicator in the InjectionIII menu bar icon
How It Works
Ora’s hot reloading setup involves several components working together:1. Bundle Loading
The app loads InjectionIII bundles at startup in Debug builds:oraApp.swift
2. Build Configuration
Special Debug-only build settings inproject.yml enable hot reloading:
project.yml
EMIT_FRONTEND_COMMAND_LINES = YES
- Tells Xcode to output the exact compiler flags used for each file
- InjectionIII reads these flags to recompile individual files correctly
- Without this, InjectionIII can’t match your build configuration
-Xlinker -interposable
- Makes function calls replaceable at runtime
- Allows InjectionIII to swap out old implementations with new ones
- Without this, code changes wouldn’t take effect until a full rebuild
3. Inject Package Integration
Ora uses the Inject Swift package to observe injection events:project.yml
@ObserveInjectionproperty wrapper to detect code changes.enableInjection()view modifier to trigger re-rendering
4. View Instrumentation
Root views use@ObserveInjection to respond to code changes:
OraRoot.swift
@ObserveInjectiondetects the change.enableInjection()triggers view invalidation- SwiftUI re-evaluates the view hierarchy
- Changes appear on screen
Adding Hot Reload Support to New Views
To enable hot reloading in your own views:You don’t need to add this to every view—only root-level views or views you’re actively developing. Child views will update automatically when their parent re-renders.
Usage Tips
Making Changes
- Edit and save: Modify any Swift file and save (⌘S)
- Watch for confirmation: InjectionIII shows a notification when injection succeeds
- See results: Changes appear immediately in your running app
What You Can Change
Works well:- SwiftUI view bodies
- Computed properties
- Function implementations
- Colors, fonts, spacing
- Layout changes
- String content
- Adding/removing/reordering stored properties
- Changing struct/class definitions
- Modifying initializers
- Adding new files (must build once first)
Troubleshooting Changes
If changes don’t appear:- Check the InjectionIII status: Green icon = connected, Red = disconnected
- Verify Debug build: Release builds don’t support hot reloading
- Look for errors: InjectionIII shows compilation errors in its console
- Try a full rebuild: Some changes require recompiling the whole app
Limitations
Stored Property Changes
You cannot add, remove, or reorder stored properties during injection:Private Members in Extensions
Private members in extensions may not inject correctly:internal access (the default) during active development:
private before committing if needed.
SwiftData Models
Changes to@Model classes may not hot reload properly. For model changes, do a full rebuild.
Performance Impact
Hot reloading has zero impact on Release builds. All InjectionIII code is gated behind
#if DEBUG and completely absent from production builds.- Slightly larger binary size (due to
-Xlinker -interposable) - Minimal runtime performance difference
- Worth it for the development speed boost
- No InjectionIII dependencies
- No bundle loading
- No linker flags
- Fully optimized
Advanced Configuration
InjectionIII Settings
Access InjectionIII preferences via the menu bar icon:- File Watcher: Choose between FSEvents (faster) or kqueue (more compatible)
- Notifications: Enable/disable injection success/failure notifications
- Auto-unhide: Automatically bring the simulator/app to the front after injection
Excluding Files
To prevent InjectionIII from watching certain files, add them to a.injectionignore file:
.injectionignore
Injection Logging
InjectionIII logs all compilation and injection events. View logs:- Click the InjectionIII menu bar icon
- Select Show Console
- View real-time compilation output and errors
Frequently Asked Questions
Why isn’t hot reloading working?
Check these:- InjectionIII is running and shows a green icon
- You opened the correct project folder in InjectionIII
- Running a Debug build (not Release)
- The file you’re editing is part of the Xcode target
- No compilation errors (check InjectionIII console)
Can I use this in production?
No. Hot reloading is Debug-only and completely disabled in Release builds. It’s purely a development tool.Does this work with SwiftUI previews?
InjectionIII and Xcode Previews serve different purposes:- Previews: Fast iteration on isolated views
- InjectionIII: Live updates in your fully running app
Is there a performance cost?
Debug builds are slightly slower due to-Xlinker -interposable, but the difference is minimal. Release builds have zero overhead.
What about Simulator vs. Real Device?
InjectionIII works with both macOS apps and iOS apps running in the Simulator. It does not support physical iOS devices. For Ora Browser (a macOS app), you’re always running on the real device (your Mac), so this isn’t a concern.Resources
InjectionIII GitHub
Official InjectionIII repository and documentation
Inject Package
Swift package for SwiftUI hot reloading integration
Development Setup
Complete development environment setup guide
Architecture
Learn about Ora’s architecture
