Ios architecture
Skill almasumdev/awesome-ios-agent-skills/.github/skills/architecture/ios-architecture
Expert guidance on modern iOS application architecture using Clean Architecture, SwiftUI-first layering, and Swift Package Manager (SPM) feature modularization. Use this when asked about project structure, module graph, or DI.From its SKILL.md
npx -y skills add almasumdev/awesome-ios-agent-skills --skill ios-architectureAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
5.2 KB, ~1.1k tokens by cl100k_base, as published. Nobody here has run it
iOS Modern Architecture & Modularization
Instructions
When designing or refactoring an iOS application, follow Clean Architecture principles. Dependencies flow inward toward pure Swift domain code.
1. High-Level Layers
- Presentation Layer
- Responsibility: Rendering views and handling user intent.
- Components:
View,@Observablemodels (Observation framework), TCAReducers, coordinators. - Dependencies: Domain layer (
UseCases or repository protocols) only.
- Domain Layer (Pure Swift)
- Responsibility: Business rules and entities.
- Components: Value-type entities,
UseCaseprotocols, repository protocols. - Rule: Must not import
UIKit,SwiftUI, or persistence frameworks. Ship as its own SPM package for enforcement.
- Data Layer
- Responsibility: Fetching, caching, persisting data.
- Components: Repository implementations, remote clients (
URLSession), local stores (SwiftData/Core Data), DTOs + mappers.
2. Architectural Styles
| Style | When to pick it |
|---|---|
| MV | Small/medium SwiftUI apps. View binds directly to an @Observable model. |
| MVVM | Teams migrating from UIKit; explicit ViewModel boundary and testability focus. |
| TCA | Large apps needing exhaustive testing, time-travel debugging, strict effects. |
Pick one per app and stay consistent. Mixing styles is acceptable at the feature module boundary, not inside a feature.
3. Dependency Injection
Use initializer injection with protocol abstractions. For SwiftUI, expose shared dependencies through @Environment values or a lightweight container. Avoid @EnvironmentObject for pure service graphs — prefer constructors.
protocol ArticleRepository: Sendable {
func latest() async throws -> [Article]
}
@Observable
final class ArticleListModel {
private let repository: any ArticleRepository
var articles: [Article] = []
var error: Error?
init(repository: any ArticleRepository) {
self.repository = repository
}
@MainActor
func load() async {
do { articles = try await repository.latest() }
catch { self.error = error }
}
}
An environment key for cross-cutting services:
private struct AnalyticsKey: EnvironmentKey {
static let defaultValue: any Analytics = NoopAnalytics()
}
extension EnvironmentValues {
var analytics: any Analytics {
get { self[AnalyticsKey.self] }
set { self[AnalyticsKey.self] = newValue }
}
}
4. Modularization with SPM
Split the app into small SPM packages. A workable layout:
MyApp/
├── MyApp.xcodeproj # Thin shell target
├── App/ # Composition root, @main
├── Packages/
│ ├── Core/ # Logging, Env, shared types
│ ├── DesignSystem/ # Tokens, shared SwiftUI components
│ ├── Domain/ # Pure Swift entities + protocols
│ ├── Data/ # Repository implementations
│ └── Features/
│ ├── Articles/
│ │ ├── ArticlesDomain/
│ │ ├── ArticlesData/
│ │ └── ArticlesUI/
│ └── Profile/
└── Package.swift # Root manifest when using a single package
Example Package.swift slice:
// swift-tools-version: 5.10
import PackageDescription
let package = Package(
name: "Articles",
platforms: [.iOS(.v15)],
products: [
.library(name: "ArticlesUI", targets: ["ArticlesUI"])
],
dependencies: [
.package(path: "../Domain"),
.package(path: "../DesignSystem")
],
targets: [
.target(name: "ArticlesDomain"),
.target(name: "ArticlesData", dependencies: ["ArticlesDomain"]),
.target(name: "ArticlesUI", dependencies: ["ArticlesDomain", "DesignSystem"]),
.testTarget(name: "ArticlesDomainTests", dependencies: ["ArticlesDomain"])
]
)
5. Composition Root
Assemble real implementations in the @main App only. Features depend on protocols:
@main
struct MyApp: App {
private let container = AppContainer.live()
var body: some Scene {
WindowGroup {
RootView()
.environment(container.articlesModel)
.environment(\.analytics, container.analytics)
}
}
}
Checklist
- Domain package has no
UIKit/SwiftUI/ persistence imports. - Repositories expose domain entities only — never DTOs.
- One architecture style per app; features do not import siblings directly.
- Composition happens in the app target; features depend on protocols.
- Each feature module ships with its own test target.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.