Skip to content

trunghvbk/clean_architecture_iOS_swiftUI

Repository files navigation

Clean Architecture iOS Application with SwiftUI

This project demonstrates the implementation of Clean Architecture principles in an iOS application using SwiftUI for the presentation layer. It provides a structured, maintainable, and testable codebase by separating concerns into distinct layers.

Table of Contents

Project Structure

CleanArchitectureIOSAppSwiftUI/
├── Domain/                 # Domain Layer
│   ├── Entities/           # Business models
│   ├── UseCases/           # Business logic
│   ├── Repositories/       # Repository interfaces
│   └── Protocols/          # Domain protocols and errors
├── Data/                   # Data Layer
│   ├── Repositories/       # Repository implementations
│   ├── DataSources/        # Data sources
│   │   ├── Remote/         # Remote data sources (API)
│   │   └── Local/          # Local data sources (Database, UserDefaults)
│   └── Models/             # Data models (DTOs)
├── Presentation/           # Presentation Layer
│   ├── ViewModels/         # View models
│   ├── Views/              # SwiftUI views
│   └── UIModels/           # UI models
├── DI/                     # Dependency Injection
│   ├── DIContainer.swift   # DI container
│   └── ServiceLocator.swift # Service locator
└── CleanArchitectureApp.swift # Application entry point

Architecture Overview

This project follows the Clean Architecture principles introduced by Robert C. Martin (Uncle Bob). The architecture is divided into three main layers:

  1. Domain Layer: Contains business logic and rules, entities, use cases, and repository interfaces.
  2. Data Layer: Implements repository interfaces from the domain layer and handles data operations.
  3. Presentation Layer: Handles UI logic using SwiftUI, including view models and views.

The key principle is the dependency rule: source code dependencies only point inward. Inner layers don't know anything about outer layers.

Layers

Domain Layer

The Domain Layer is the core of the application and contains:

  • Entities: Business models that represent the core concepts of the application.
  • Use Cases: Business logic that orchestrates the flow of data between entities and repositories.
  • Repository Interfaces: Abstractions that define how to access data.
  • Protocols: Common interfaces and error types used across the domain layer.

The Domain Layer is independent of any other layers and doesn't have any dependencies on frameworks or external libraries.

Data Layer

The Data Layer implements the repository interfaces defined in the Domain Layer and is responsible for:

  • Repository Implementations: Concrete implementations of the repository interfaces.
  • Data Sources: Components that handle data operations from different sources:
    • Remote Data Sources: Handle API calls and network operations.
    • Local Data Sources: Handle local storage operations (UserDefaults, CoreData, etc.).
  • Data Models (DTOs): Data Transfer Objects that map between domain entities and external data formats.

Presentation Layer (SwiftUI)

The Presentation Layer handles the UI and user interactions using SwiftUI:

  • View Models: Transform domain data into a format that can be easily displayed in the UI and provide reactive state management using Combine framework.
  • Views: SwiftUI views that display data and handle user interactions.
  • UI Models: Models specifically designed for UI representation, conforming to protocols like Identifiable for SwiftUI lists.

Key SwiftUI concepts used:

  • @ObservedObject: To observe changes in view models
  • @Published: To publish state changes from view models
  • @State: For local view state management
  • @Environment: To access environment values like dismiss actions

Dependency Injection

The project uses two approaches for dependency injection:

  1. DIContainer: A factory-based approach that creates and provides dependencies.
  2. ServiceLocator: A service locator pattern that allows resolving dependencies from anywhere in the app.

Both approaches help to maintain loose coupling between components and make the code more testable.

Sample Feature

The project includes a sample User Management feature that demonstrates how all layers work together:

  • Domain Layer: User entity, UserRepository interface, and use cases for user operations.
  • Data Layer: UserRepositoryImpl, UserRemoteDataSource, and UserLocalDataSource.
  • Presentation Layer: UserViewModel, UserListView, UserDetailView, and form views.

The feature allows:

  • Viewing a list of users
  • Viewing user details
  • Adding new users
  • Editing existing users
  • Deleting users

Getting Started

To use this project as a template for your iOS application:

  1. Clone the repository
  2. Replace the sample User feature with your own domain entities and use cases
  3. Implement your own data sources and repositories
  4. Create your own view models and SwiftUI views
  5. Update the dependency injection setup as needed

Best Practices

  • Single Responsibility Principle: Each class has only one reason to change.
  • Dependency Inversion: High-level modules don't depend on low-level modules.
  • Interface Segregation: Clients shouldn't depend on methods they don't use.
  • Testability: The architecture makes it easy to write unit tests for each layer.
  • Separation of Concerns: Each layer has its own responsibility.
  • Loose Coupling: Components are loosely coupled through interfaces and dependency injection.
  • SwiftUI Best Practices:
    • Use ObservableObject and @Published for reactive state management
    • Keep views small and composable
    • Use preview providers for rapid UI development

SwiftUI vs UIKit Implementation

This project demonstrates Clean Architecture with SwiftUI, which differs from a UIKit implementation in several ways:

Key Differences

  1. Declarative vs Imperative UI:

    • SwiftUI uses a declarative approach where you describe what the UI should look like
    • UIKit uses an imperative approach where you manually manage view hierarchies
  2. State Management:

    • SwiftUI uses property wrappers like @State, @ObservedObject, and @Published
    • UIKit typically uses delegation patterns and callbacks
  3. View Lifecycle:

    • SwiftUI has simpler lifecycle management with onAppear and onDisappear
    • UIKit has more complex lifecycle methods like viewDidLoad, viewWillAppear, etc.
  4. Navigation:

    • SwiftUI uses NavigationView and NavigationLink for navigation
    • UIKit uses UINavigationController and manual push/pop operations
  5. Data Flow:

    • SwiftUI has built-in reactive data flow with Combine framework integration
    • UIKit requires manual implementation of reactive patterns or third-party libraries

Despite these differences, the core Clean Architecture principles remain the same, with the domain and data layers being identical between the two implementations.

About

Clean architecture project for iOS SwiftUI Application

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages