Refactor high-complexity React components in Dify frontend. Use when `pnpm analyze-component...
npx skills add arclabs-studio/ARCKnowledge --skill "arc-swift-architecture"
Install specific skill from multi-skill repository
# Description
|
# SKILL.md
name: arc-swift-architecture
description: |
ARC Labs Studio Swift architecture patterns and principles. Covers Clean
Architecture with three layers (Presentation, Domain, Data), MVVM+Coordinator
pattern with ARCNavigation Router, SOLID principles applied to Swift, Protocol-Oriented
Design, dependency injection, layer boundaries, data flow, and singleton patterns.
INVOKE THIS SKILL when:
- Designing a new feature or module architecture
- Setting up layer boundaries (Presentation/Domain/Data)
- Implementing MVVM+C pattern with ViewModels and Routers
- Creating Use Cases, Entities, or Repository protocols
- Reviewing code for architectural compliance
- Discussing or explaining architectural decisions
ARC Labs Studio - Swift Architecture Patterns
When to Use This Skill
Use this skill when you need to:
- Design new features or modules following Clean Architecture
- Refactor existing code to improve architecture
- Answer questions about layer boundaries and dependencies
- Implement MVVM+C pattern (Model-View-ViewModel-Coordinator)
- Set up dependency injection properly
- Make Protocol-Oriented Design decisions
- Review code architecture and provide feedback
- Explain architectural patterns to team members
- Resolve dependency issues between layers
- Design domain entities and use cases
- Understand when singletons are appropriate
Quick Reference
Clean Architecture - Three Layers
βββββββββββββββββββββββββββββββββββββββββββββββ
β PRESENTATION LAYER β
β SwiftUI Views β’ ViewModels β’ Routers β
β (User Interface & Navigation) β
βββββββββββββββββββββββββββββββββββββββββββββββ€
β DOMAIN LAYER β
β Entities β’ Use Cases β’ Protocols β
β (Business Logic & Rules) β
βββββββββββββββββββββββββββββββββββββββββββββββ€
β DATA LAYER β
β Repositories β’ Data Sources β’ DTOs β
β (Data Access & External Services) β
βββββββββββββββββββββββββββββββββββββββββββββββ
β² DEPENDENCY RULE: Dependencies flow INWARD only β²
Key Principle: Inner layers NEVER depend on outer layers.
- Presentation can depend on Domain
- Domain NEVER depends on Presentation or Data
- Data can depend on Domain (implements protocols)
Layer Structure
Sources/
βββ Presentation/
β βββ Features/
β β βββ [FeatureName]/
β β βββ View/ # SwiftUI Views (*View.swift)
β β βββ ViewModel/ # ViewModels (*ViewModel.swift)
β β βββ Router/ # Routers (*Router.swift)
β βββ Shared/ # Reusable UI components
β
βββ Domain/
β βββ Entities/ # Core business objects
β βββ UseCases/ # Business logic (*UseCase.swift)
β βββ Repositories/ # Protocol definitions only
β
βββ Data/
βββ Repositories/ # Protocol implementations
βββ DataSources/ # API clients, Database managers
βββ Models/ # DTOs, API responses
MVVM+C Pattern with ARCNavigation
// Route Definition (enum-based, type-safe)
enum AppRoute: Route {
case home
case profile(userID: String)
case settings
@ViewBuilder
func view() -> some View {
switch self {
case .home: HomeView()
case .profile(let userID): ProfileView(userID: userID)
case .settings: SettingsView()
}
}
}
// View (Presentation Layer - pure presentation)
struct UserListView: View {
@Environment(Router<AppRoute>.self) private var router
@State var viewModel: UserListViewModel
var body: some View {
List(viewModel.users) { user in
Button(user.name) {
router.navigate(to: .profile(userID: user.id))
}
}
}
}
// ViewModel (Presentation Layer - coordinates UI state)
@Observable
@MainActor
final class UserListViewModel {
private(set) var users: [User] = []
private(set) var isLoading = false
private let getUsersUseCase: GetUsersUseCaseProtocol
init(getUsersUseCase: GetUsersUseCaseProtocol) {
self.getUsersUseCase = getUsersUseCase
}
func loadUsers() async {
isLoading = true
users = (try? await getUsersUseCase.execute()) ?? []
isLoading = false
}
}
// Use Case Protocol (Domain Layer)
protocol GetUsersUseCaseProtocol: Sendable {
func execute() async throws -> [User]
}
// Use Case (Domain Layer - business logic)
final class GetUsersUseCase: GetUsersUseCaseProtocol {
private let repository: UserRepositoryProtocol
init(repository: UserRepositoryProtocol) {
self.repository = repository
}
func execute() async throws -> [User] {
let users = try await repository.getUsers()
return users.filter { $0.isActive } // Business rule
}
}
// Entity (Domain Layer - pure business object)
struct User: Identifiable, Equatable, Sendable {
let id: UUID
let name: String
let email: String
let isActive: Bool
}
// Repository Protocol (Domain Layer)
protocol UserRepositoryProtocol: Sendable {
func getUsers() async throws -> [User]
}
// Repository Implementation (Data Layer)
final class UserRepositoryImpl: UserRepositoryProtocol {
private let remoteDataSource: UserRemoteDataSourceProtocol
func getUsers() async throws -> [User] {
let dtos = try await remoteDataSource.fetchUsers()
return dtos.map { $0.toDomain() }
}
}
SOLID Principles Quick Guide
- Single Responsibility: Each class has one reason to change
- Open/Closed: Open for extension, closed for modification
- Liskov Substitution: Subtypes must be substitutable for base types
- Interface Segregation: Many specific protocols > one general
- Dependency Inversion: Depend on abstractions (protocols), not concretions
Protocol-Oriented Design
// Define protocols in Domain layer
protocol UserRepository: Sendable {
func fetchUsers() async throws -> [User]
func saveUser(_ user: User) async throws
}
// Implement in Data layer
final class RemoteUserRepository: UserRepository {
func fetchUsers() async throws -> [User] { /* ... */ }
func saveUser(_ user: User) async throws { /* ... */ }
}
// Inject via protocols (Dependency Inversion)
final class GetUsersUseCase {
private let repository: UserRepository // Protocol, not concrete type
init(repository: UserRepository) {
self.repository = repository
}
}
Dependency Injection Pattern
// Composition Root (App level)
@MainActor
final class AppDependencies {
func makeUserListView() -> UserListView {
let repository = RemoteUserRepository()
let useCase = GetUsersUseCase(repository: repository)
let viewModel = UserListViewModel(getUsersUseCase: useCase)
return UserListView(viewModel: viewModel)
}
}
When Singletons Are Appropriate
Use singletons ONLY for truly global, unique resources:
- Hardware access (camera, location)
- App configuration
- Analytics/logging
Always wrap with protocols for testability:
protocol LocationServiceProtocol: Sendable {
func getCurrentLocation() async throws -> Location
}
final class LocationService: LocationServiceProtocol {
static let shared = LocationService()
private init() {}
func getCurrentLocation() async throws -> Location { /* ... */ }
}
Detailed Documentation
For complete patterns, examples, and guidelines:
- @clean-architecture.md - Complete Clean Architecture guide with examples
- @mvvm-c.md - MVVM+Coordinator pattern implementation details
- @solid-principles.md - SOLID principles applied to Swift
- @protocol-oriented.md - Protocol-Oriented Programming best practices
- @singletons.md - When and how to use singletons safely
- @domain.md - Domain layer: Entities, Use Cases, Repository Protocols
Anti-Patterns to Avoid
- β ViewModels depending on concrete Repository implementations
- β Domain layer importing UIKit or SwiftUI
- β Data layer containing business logic
- β Massive ViewModels doing everything
- β Global singletons without protocol abstraction
- β Direct navigation without Router (NavigationLink, .sheet)
- β Business logic in Views
- β Reverse dependencies (Domain importing Presentation/Data)
Related Skills
When working on architecture, you may also need:
| If you need... | Use |
|---|---|
| Data layer implementation | /arc-data-layer |
| Presentation layer patterns | /arc-presentation-layer |
| Testing patterns | /arc-tdd-patterns |
| Code quality standards | /arc-quality-standards |
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.