This repository demonstrates how to implement the VIPER architecture in a modern SwiftUI project. VIPER is a clean architecture design pattern that enforces separation of concerns, making your codebase modular, testable, and scalable.
- View → Displays UI and forwards user interactions to the Presenter.
- Interactor → Handles business logic (fetching data, validation, transformations).
- Presenter → Connects View & Interactor. Prepares data for the UI.
- Entity → Represents the model/data structures used by the Interactor.
- Router → Handles navigation and screen flow.
This pattern was originally designed for UIKit, but here we explore how to adapt VIPER to SwiftUI effectively.
SwiftUI already provides MVVM by default, but for larger projects, MVVM can get bloated (e.g., view models mixing business logic, state management, and navigation).
By applying VIPER: ✅ Clear separation of UI, logic, and routing ✅ Better testability of each layer ✅ Modular and reusable code ✅ More maintainable codebase for scaling projects
ViperSwiftUI/
│── Modules/
│ └── ExampleModule/
│ ├── View/
│ │ └── ExampleView.swift
│ ├── Presenter/
│ │ └── ExamplePresenter.swift
│ ├── Interactor/
│ │ └── ExampleInteractor.swift
│ ├── Router/
│ │ └── ExampleRouter.swift
│ └── Entity/
│ └── ExampleEntity.swift
│
│── App/
│ └── ViperSwiftUIApp.swift
│
└── Resources/
- Declares the UI using SwiftUI.
- Listens to Presenter’s data.
- Sends user actions to the Presenter.
struct ExampleView: View {
@ObservedObject var presenter: ExamplePresenter
var body: some View {
VStack {
Text(presenter.title)
Button("Tap Me") {
presenter.onButtonTap()
}
}
}
}
- Connects the View with the Interactor.
- Holds observable state for SwiftUI.
- Prepares data for display.
class ExamplePresenter: ObservableObject {
@Published var title: String = "Hello VIPER"
private let interactor: ExampleInteractor
private let router: ExampleRouter
init(interactor: ExampleInteractor, router: ExampleRouter) {
self.interactor = interactor
self.router = router
}
func onButtonTap() {
title = interactor.fetchGreeting()
}
}
- Handles business logic.
- Can call APIs, databases, or services.
class ExampleInteractor {
func fetchGreeting() -> String {
return "Hello from Interactor 🚀"
}
}
- Defines data models used by the Interactor.
struct ExampleEntity {
let message: String
}
- Manages navigation between SwiftUI views.
class ExampleRouter {
func navigateToNextView() -> some View {
return NextView()
}
}
- Fully SwiftUI compatible VIPER pattern.
- Clear separation of UI, business logic, and navigation.
- Each component is independently testable.
- Scales well for enterprise-level apps.
1: Clone the repo:
git clone https://github.com/usamajavedswl/ViperSwiftUI.git
2: Open the project in Xcode. 3: Run on iOS Simulator or device.
- Contributions are welcome! Feel free to:
- Open issues
- Submit pull requests
- Suggest improvements
This project is licensed under the MIT License – free to use and modify.