agentsclimarketplace

Swift architecture

Skill Mattakushi432/Claude-Code-Skills-Custom-DevTools-Pack/plugins/devtools-pack/skills/swift-architecture

When to activate: iOS/macOS app architecture, MVVM, TCA, Clean Architecture, dependency injection, modular design in Swift appsFrom its SKILL.md

Install
npx -y skills add Mattakushi432/Claude-Code-Skills-Custom-DevTools-Pack --skill swift-architecture

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 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

Swift App Architecture Patterns

MVVM with SwiftUI

// Model — pure data, no UI dependencies
struct Article: Identifiable, Codable {
    let id: UUID
    let title: String
    let body: String
    let publishedAt: Date
}

// ViewModel — transforms model for display, owns async operations
@MainActor
final class ArticleListViewModel: ObservableObject {
    @Published private(set) var articles: [Article] = []
    @Published private(set) var isLoading = false
    @Published var errorMessage: String?

    private let repository: any ArticleRepository

    init(repository: any ArticleRepository) {
        self.repository = repository
    }

    func load() async {
        isLoading = true
        defer { isLoading = false }
        do {
            articles = try await repository.fetchAll()
        } catch {
            errorMessage = error.localizedDescription
        }
    }
}

// View — purely declarative, no business logic
struct ArticleListView: View {
    @StateObject private var vm: ArticleListViewModel

    init(repository: any ArticleRepository) {
        _vm = StateObject(wrappedValue: ArticleListViewModel(repository: repository))
    }

    var body: some View {
        Group {
            if vm.isLoading { ProgressView() }
            else { List(vm.articles) { ArticleRow(article: $0) } }
        }
        .task { await vm.load() }
        .alert("Error", isPresented: .constant(vm.errorMessage != nil)) { }
              message: { Text(vm.errorMessage ?? "") }
    }
}

Repository Pattern

protocol ArticleRepository {
    func fetchAll() async throws -> [Article]
    func fetch(id: UUID) async throws -> Article?
    func save(_ article: Article) async throws
}

struct RemoteArticleRepository: ArticleRepository {
    let client: APIClient

    func fetchAll() async throws -> [Article] {
        try await client.get("/articles", as: [Article].self)
    }

    func fetch(id: UUID) async throws -> Article? {
        try await client.get("/articles/\(id)", as: Article.self)
    }

    func save(_ article: Article) async throws {
        try await client.post("/articles", body: article) as Article
    }
}

// In-memory implementation for tests/previews
final class InMemoryArticleRepository: ArticleRepository {
    var articles: [Article] = []
    func fetchAll() async throws -> [Article] { articles }
    func fetch(id: UUID) async throws -> Article? { articles.first { $0.id == id } }
    func save(_ article: Article) async throws { articles.append(article) }
}

Dependency Injection Container

// Using point-free/swift-dependencies style
import Dependencies

extension DependencyValues {
    var articleRepository: any ArticleRepository {
        get { self[ArticleRepositoryKey.self] }
        set { self[ArticleRepositoryKey.self] = newValue }
    }
}

private enum ArticleRepositoryKey: DependencyKey {
    static let liveValue: any ArticleRepository = RemoteArticleRepository(client: .live)
    static let testValue: any ArticleRepository = InMemoryArticleRepository()
    static let previewValue: any ArticleRepository = InMemoryArticleRepository(articles: .preview)
}

// Usage in ViewModel
@MainActor
final class ArticleListViewModel: ObservableObject {
    @Dependency(\.articleRepository) var repository
}

Clean Architecture Layers

Presentation (SwiftUI views + ViewModels)
      ↓
Domain (Use Cases / Interactors)
      ↓
Data (Repositories → Remote + Local)
// Domain layer — use case
struct FetchArticlesUseCase {
    let remote: any ArticleRepository
    let local: any ArticleRepository

    func execute() async throws -> [Article] {
        do {
            let articles = try await remote.fetchAll()
            for article in articles { try await local.save(article) }
            return articles
        } catch {
            // Fallback to local cache
            return try await local.fetchAll()
        }
    }
}

Modular Feature Design

// Each feature is a standalone SPM module
// Feature/ArticleFeature/Sources/ArticleListView.swift
public struct ArticleListView: View {
    public init(store: ArticleStore) { self.store = store }
    private let store: ArticleStore
    // ...
}

// App target wires features together
import ArticleFeature
import ProfileFeature

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            TabView {
                ArticleListView(store: .live)
                ProfileView(store: .live)
            }
        }
    }
}

Common Anti-Patterns

  • Fat ViewControllers / fat Views — move business logic to ViewModel or UseCase
  • Views depending on networking — always go through ViewModel → Repository
  • Singleton abuse — use DI instead; singletons make testing hard
  • Circular module dependencies — extract shared types to a Core module
  • Tight coupling between features — communicate via protocols or shared events, not direct imports

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.