Part of PatternKit, a side-by-side reference codebase where the same small Tasks CRUD app is implemented once per architecture pattern across iOS and Android. Every module ships identical behaviour — the same domain model, the same three screens, the same mock data layer — so the only thing that varies is the architecture itself.
This module is the Clean Architecture flavour on UIKit. It keeps MVVM in the presentation layer but interposes a domain layer of use cases between the view models and the data layer, and drives navigation with a classic delegate-based Coordinator owning a UINavigationController. It's the imperative counterpart to the SwiftUI Clean module — same layering, same use cases, rendered the way pre-SwiftUI production apps are built — and the direct Clean-axis sibling of the MVVM-UIKit module: same UI stack, but with the domain layer added.
- Language: Swift
- UI: UIKit (
UITableView, view controllers, programmatic flow) - Architecture: Clean Architecture (Domain / Data / Presentation) with MVVM presentation + Coordinator
- DI: Manual constructor injection (
AppContainer) - Navigation: Coordinator (
AppCoordinatorowning aUINavigationController, per-screen delegate protocols) - Deployment target: iOS 17.0 minimum (built against the iOS 26.5 SDK)
- Bundle ID:
com.preetanshumishra.PatternKitiOSCleanUIKit
A single-user task list. One entity (TaskItem: title, optional notes, optional due date, priority, completion). Three screens:
- List (
TaskListViewController) — filter (All / Active / Completed), sort by due date or priority, swipe-to-delete,+bar button to create. - Detail (
TaskDetailViewController) — read-only fields, toggle completion, edit, delete. - Form (
TaskFormViewController) — create or edit (mode-driven), title validation (≤ 80 chars), due-date validation (not in the past), 600 ms mock async save.
Data comes from MockTaskRepository — an in-memory store seeded with ~12 tasks, with configurable artificial latency and failure rate. No real network, no local persistence — intentionally, so the architecture stays the focus.
Five single-responsibility use cases sit between the presentation and data layers:
FetchTasksUseCase,CreateTaskUseCase,UpdateTaskUseCase,DeleteTaskUseCase,ToggleTaskCompletionUseCase
Each depends only on the TaskRepository protocol (declared in Domain/). View models compose use cases rather than touching the repository directly — the one structural difference from the MVVM-UIKit module. The completion-toggle and updatedAt-stamp rules that lived in the MVVM-UIKit view models now live in their use cases, reusable and unit-testable in isolation from any UI.
AppDelegate+SceneDelegate— classic app lifecycle and window setup, no SwiftUIApp. The scene builds and retains theAppCoordinator.UITableView+TaskCell— list rendering with a custom cell.- View models (
TaskListViewModel,TaskFormViewModel) expose state and bind to view controllers via closures/callbacks — the manual binding that SwiftUI gives you for free.
Manual constructor-based DI, no third-party container. AppContainer builds the repository, wires it into the use cases, and injects those into the view models, which are in turn handed to their view controllers.
This is the classic, delegate-based Coordinator. Each screen declares a thin protocol of the navigation events it can emit (TaskListCoordinating, TaskDetailCoordinating, TaskFormCoordinating); the view controllers hold a weak reference to one of those protocols and fire semantic events (taskListDidSelect, taskDetailDidRequestEdit, taskFormDidSave, …) rather than pushing, presenting, or popping anything themselves. AppCoordinator owns the UINavigationController and the shared list view model, conforms to all three protocols, and decides every transition in one place. The view controllers therefore depend only on their protocol — never on each other or on the navigation controller.
PatternKitiOSCleanUIKit/
├── Domain/
│ ├── TaskItem, Priority, TaskFilter, TaskSort
│ ├── TaskRepository.swift # protocol
│ └── UseCases/ # five use cases
├── Data/ # MockTaskRepository, seed data
├── ViewModels/ # TaskListViewModel, TaskFormViewModel
├── ViewControllers/ # List / Detail / Form controllers + TaskCell
├── Coordinator/ # AppCoordinator + per-screen coordinating protocols
├── AppContainer.swift
├── AppDelegate.swift
└── SceneDelegate.swift
Open PatternKitiOSCleanUIKit.xcodeproj in Xcode, then ⌘R to build and run (⌘U for tests).