Habit Rabbit is a SwiftUI demo project showcasing modern iOS development patterns. I open-sourced this repository to highlight my approach to SwiftUI architecture, SwiftData integration, and custom UI design.
The app avoids massive views by keeping domain logic decoupled and utilizing the @Observable macro alongside Swift's Environment.
-
Explicit Dependency Injection:
Rather than relying solely on SwiftUI's implicit data flow, the
ModelContaineris explicitly initialized at the app root (HabitRabbit.swift). ItsmainContextis safely passed into a centralDashboard.Manager, which is then injected into the view hierarchy via.environment(). -
Manager Lifecycle & View Model Caching:
To prevent performance degradation and state resets in dynamic grids, the app does not blindly recreate view models. The
Dashboard.Manageracts as a factory, maintaining a[PersistentIdentifier: Habit.Card.Manager]cache. This maps SwiftData models to stable, long-living@Observablecard managers, ensuring fluid redraws and strict separation of concerns. -
Reusable Forms & Focus Management:
Data entry is handled by a highly reusable
Dashboard.Sheetcomponent that drives both the "Add" and "Edit" workflows via anInitialValuesstruct. The form includes production-level UX details, such as programmatic keyboard focus management (FocusState) to smoothly advance users through the input fields.
SwiftData is used to handle data persistence efficiently and maintain a smooth scrolling experience, even as historical data grows:
-
Relational Models:
The schema separates the
Habitdefinition from its historicalHabit.Valueentries, utilizing cascade delete rules to maintain data integrity. -
Caching & Prefetching (Card Level):
The
Card.Managerimplements a local dictionary cache to prefetch active rolling windows (e.g., a 30-day core with 14-day buffers). This allows for smooth pagination through dates without constantly hitting the persistent store. -
Cursor-Based Pagination (Detail Level):
To ensure memory safety for habits with years of history, the
DetailView.Managerimplements cursor-based pagination. UsingfetchOffsetandfetchLimit, it loads historical records in discrete chunks (100 at a time) only when requested by the user.
The interface features custom components and uses modern SwiftUI transition APIs to create a responsive, fluid feel:
-
Modern View Transitions:
Layout morphing—such as switching a card between daily, weekly, and monthly views—is handled seamlessly using
.geometryGroup()and.matchedGeometryEffect(). Furthermore, navigating to the Detail View utilizes the modern.navigationTransition(.zoom(sourceID:))API for continuous, fluid hero animations.
The interface has custom components and uses modern SwiftUI transition APIs to create a responsive feel:
-
View Transitions:
Layout morphing like switching a card between daily, weekly, and monthly views is handled seamlessly using
.geometryGroup(),.matchedGeometryEffect(), and.transition(.blurReplace).
screenshot.-.1.mov
-
Custom Components:
The custom
ProgressBarincludes a math function that applies a power curve to adjust mid-range values, visually offsetting the shortening caused by SwiftUI's rounded capsule caps. Additionally, the monthly view dynamically calculates column indexes to align data to the correct weekdays on the fly. -
Context-Aware Theming:
Visual elements adjust based on both the environment (light/dark mode) and the data state. For example, completing a target modifies the brightness and border width depending on whether the app is in dark mode or if the habit is considered a "good" or "bad" habit.
-
Micro-Interactions:
Numeric labels use
.monospacedDigit()and.contentTransition(.numericText())for clean tick-ups when logging data. Relevant data triggers are also tied to haptic feedback via.sensoryFeedback.
To review how these concepts are implemented, here are a few recommended starting points:
/App/Models/Habit.swift&Value.swift**: SwiftData models and fetch descriptors./Views/Card/Manager/Card.Manager.valueOperations.swift: Data caching, prefetching, and fetching logic./Views/Other/ProgressBar/ProgressBar.geometry.swift: The math logic used for the progress bar curvature correction./Views/Dashboard/Dashboard.swift: The root view demonstrating dependency injection and the main grid layout.