From swiftui-dev
Provides SwiftUI architecture patterns including MVVM with @Observable macro, protocol-based dependency injection, and type-safe NavigationStack navigation for scalable apps.
npx claudepluginhub arustydev/agents --plugin swiftui-devThis skill uses the workspace's default tool permissions.
Architecture patterns for SwiftUI applications including MVVM, navigation, dependency injection, and the @Observable macro.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
Architecture patterns for SwiftUI applications including MVVM, navigation, dependency injection, and the @Observable macro.
import SwiftUI
// ViewModel using @Observable macro (iOS 17+/macOS 14+)
@Observable
final class ContentViewModel {
var items: [Item] = []
var isLoading = false
var errorMessage: String?
private let repository: ItemRepository
init(repository: ItemRepository = .live) {
self.repository = repository
}
func loadItems() async {
isLoading = true
defer { isLoading = false }
do {
items = try await repository.fetchAll()
} catch {
errorMessage = error.localizedDescription
}
}
}
// View
struct ContentView: View {
@State private var viewModel = ContentViewModel()
var body: some View {
List(viewModel.items) { item in
ItemRow(item: item)
}
.overlay {
if viewModel.isLoading {
ProgressView()
}
}
.task {
await viewModel.loadItems()
}
}
}
// Protocol-based dependency
protocol ItemRepository: Sendable {
func fetchAll() async throws -> [Item]
func save(_ item: Item) async throws
}
// Live implementation
struct LiveItemRepository: ItemRepository {
func fetchAll() async throws -> [Item] {
// Real implementation
}
func save(_ item: Item) async throws {
// Real implementation
}
}
// Mock for testing
struct MockItemRepository: ItemRepository {
var items: [Item] = []
var shouldFail = false
func fetchAll() async throws -> [Item] {
if shouldFail { throw TestError.fetchFailed }
return items
}
func save(_ item: Item) async throws {
// Mock save
}
}
// Static factory pattern
extension ItemRepository where Self == LiveItemRepository {
static var live: LiveItemRepository { LiveItemRepository() }
}
extension ItemRepository where Self == MockItemRepository {
static var mock: MockItemRepository { MockItemRepository() }
}
// Type-safe navigation paths
enum NavigationDestination: Hashable {
case detail(Item)
case settings
case profile(userId: String)
}
struct RootView: View {
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
ContentView(path: $path)
.navigationDestination(for: NavigationDestination.self) { destination in
switch destination {
case .detail(let item):
ItemDetailView(item: item)
case .settings:
SettingsView()
case .profile(let userId):
ProfileView(userId: userId)
}
}
}
}
}
// Environment key for repository
private struct ItemRepositoryKey: EnvironmentKey {
static let defaultValue: any ItemRepository = LiveItemRepository()
}
extension EnvironmentValues {
var itemRepository: any ItemRepository {
get { self[ItemRepositoryKey.self] }
set { self[ItemRepositoryKey.self] = newValue }
}
}
// Usage in view
struct ItemListView: View {
@Environment(\.itemRepository) private var repository
@State private var items: [Item] = []
var body: some View {
List(items) { item in
Text(item.name)
}
.task {
items = try? await repository.fetchAll() ?? []
}
}
}
// Preview with mock
#Preview {
ItemListView()
.environment(\.itemRepository, MockItemRepository(items: .preview))
}
MyApp/
├── App/
│ ├── MyApp.swift # @main entry point
│ ├── AppDelegate.swift # UIKit lifecycle (if needed)
│ └── AppState.swift # Global @Observable state
│
├── Features/ # Feature modules
│ ├── Home/
│ │ ├── Views/
│ │ │ ├── HomeView.swift
│ │ │ └── HomeCard.swift
│ │ ├── ViewModels/
│ │ │ └── HomeViewModel.swift
│ │ └── Models/
│ │ └── HomeItem.swift
│ │
│ ├── Profile/
│ │ ├── Views/
│ │ ├── ViewModels/
│ │ └── Models/
│ │
│ └── Settings/
│ └── ...
│
├── Core/ # Shared infrastructure
│ ├── Repositories/
│ │ └── ItemRepository.swift
│ ├── Services/
│ │ ├── Network/
│ │ │ ├── APIClient.swift
│ │ │ ├── Endpoints.swift
│ │ │ └── NetworkError.swift
│ │ └── Persistence/
│ │ ├── DatabaseManager.swift
│ │ └── KeychainService.swift
│ └── Extensions/
│ ├── View+Extensions.swift
│ └── Date+Extensions.swift
│
├── Shared/ # Reusable UI components
│ ├── Components/
│ │ ├── LoadingView.swift
│ │ ├── ErrorView.swift
│ │ └── AsyncButton.swift
│ ├── Modifiers/
│ │ ├── CardStyle.swift
│ │ └── ShimmerEffect.swift
│ └── Styles/
│ └── ButtonStyles.swift
│
├── Utilities/ # Helpers and constants
│ ├── Constants.swift
│ ├── Logger.swift
│ └── Formatters.swift
│
├── Resources/
│ ├── Assets.xcassets # Images and colors
│ ├── Localizable.xcstrings # Localized strings (Xcode 15+)
│ └── Fonts/ # Custom fonts
│ └── CustomFont.ttf
│
└── Tests/
├── UnitTests/
│ ├── ViewModels/
│ │ └── HomeViewModelTests.swift
│ └── Services/
│ └── APIClientTests.swift
└── UITests/
├── HomeUITests.swift
└── Helpers/
└── XCUIApplication+Extensions.swift
MyAppPackage/
├── Package.swift
├── Sources/
│ ├── MyApp/ # Main app target
│ │ └── MyApp.swift
│ ├── Features/ # Feature library
│ │ ├── Home/
│ │ └── Profile/
│ ├── Core/ # Core library
│ │ ├── Networking/
│ │ └── Persistence/
│ └── SharedUI/ # UI components library
│ ├── Components/
│ └── Modifiers/
└── Tests/
├── CoreTests/
└── FeaturesTests/