Générateur de vues SwiftUI

VérifiéPrudence

Génère des vues SwiftUI bien structurées avec gestion d'état appropriée (@State, @Binding, @ObservedObject, @StateObject) et patterns spécifiques à macOS.

Spar Skills Guide Bot
DeveloppementIntermédiaire
11/03/2026
Claude Code
#swiftui#macos#swift#state-management#ui-generation

Recommandé pour

Synthèse automatique

Génère des vues SwiftUI pour macOS avec une gestion d'état explicite (@State, @Binding, @ObservedObject, @StateObject, @EnvironmentObject) à partir d'une spécification JSON décrivant la vue et ses propriétés.

Points forts

  • Schéma d'entrée/sortie explicite (nom de vue, type, propriétés d'état, ViewModel optionnel) qui rend la génération prévisible
  • Applique les bons wrappers de propriété et place le ViewModel sur @MainActor avec @Published
  • Couvre les motifs propres à macOS : NavigationSplitView, toolbar, searchable, sheet et blocs #Preview
  • Produit plusieurs fichiers identifiés par type (view, viewmodel, model) dans le résultat

Limites

  • Centré sur macOS : les motifs iOS, watchOS ou tvOS ne sont pas traités
  • S'appuie sur ObservableObject/Combine plutôt que sur la macro @Observable plus récente
  • Suppose un projet Xcode existant et ne décrit ni compilation ni tests de validation du code généré
Quand l'utiliser

À utiliser pour échafauder rapidement un nouvel écran ou composant SwiftUI macOS avec son flux de données et ses previews.

Quand l'éviter

À éviter pour du code iOS/iPadOS spécifique, pour une architecture AppKit, ou si vous voulez imposer la macro @Observable et le framework Observation.

Analyse de sécurité

Prudence
Score qualité74/100

The content is an ordinary SwiftUI code-generation reference: property-wrapper examples, view templates, and JSON schemas. There are no destructive commands, no curl|sh-style installs, no obfuscated payloads, and no attempt to exfiltrate credentials or tokens. Risk is limited to the declared tool set: Write/Edit against a caller-supplied project path plus an unused Bash grant, which warrant caution rather than a clean `safe` rating. No prompt-injection or instruction-override attempts were observed in the data.

Points d'attention
  • •Declares Bash in allowed-tools but no instruction in the skill actually uses it; the code-generation workflow only needs Read/Write/Edit/Glob/Grep, so the shell permission is broader than necessary.
  • •Takes an arbitrary `projectPath` and writes Swift files into it (Write/Edit) with no stated guardrails (e.g., path validation, overwrite confirmation), so an agent could clobber existing sources.
  • •Example code calls an undefined `DataService.shared` network/backing service; harmless as sample code, but it encourages wiring views to data services without describing where data comes from.
  • •Declared allowed-tools include Bash, Write, and Edit, which allow arbitrary command execution and file modification; however, the skill content itself contains no bash commands, no network calls, and no destructive operations — tool use is limited to generating/writing Swift source files in the user's project.
Comment cette analyse est faite

Exemples

New macOS settings screen
Generate a SwiftUI settings screen named PreferencesView for my macOS project at ~/Dev/MyApp, with @State properties for the selected tab, and a view model.
Sidebar list with search
Create a SwiftUI list view called ProjectListView in ~/Dev/MyApp using NavigationSplitView, a @StateObject view model, and a searchable field wired to the view model.
Reusable component
Generate a reusable SwiftUI component named TagChipView for macOS in ~/Dev/MyApp, taking a @Binding for the selected tag and no view model.

name: swiftui-view-generator description: Generate SwiftUI views with proper state management (@State, @Binding, @ObservedObject, @StateObject) and macOS-specific patterns allowed-tools: Read, Write, Edit, Bash, Glob, Grep tags: [swiftui, macos, swift, ui, apple]

swiftui-view-generator

Generate SwiftUI views with proper state management for macOS applications. This skill creates well-structured SwiftUI components using @State, @Binding, @ObservedObject, @StateObject, and @EnvironmentObject property wrappers.

Capabilities

  • Generate SwiftUI views with proper state management
  • Create reusable view components
  • Set up data flow with Combine
  • Implement navigation patterns
  • Generate macOS-specific UI elements
  • Create preference-based layouts
  • Set up environment values
  • Generate preview providers

Input Schema

{
  "type": "object",
  "properties": {
    "projectPath": {
      "type": "string",
      "description": "Path to the Swift project"
    },
    "viewName": {
      "type": "string",
      "description": "Name of the view to generate"
    },
    "viewType": {
      "enum": ["screen", "component", "list", "form", "settings", "sheet"],
      "default": "screen"
    },
    "stateProperties": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "type": { "type": "string" },
          "wrapper": { "enum": ["State", "Binding", "ObservedObject", "StateObject", "EnvironmentObject"] }
        }
      }
    },
    "includeViewModel": {
      "type": "boolean",
      "default": true
    },
    "macOSSpecific": {
      "type": "boolean",
      "default": true
    }
  },
  "required": ["projectPath", "viewName"]
}

Output Schema

{
  "type": "object",
  "properties": {
    "success": { "type": "boolean" },
    "files": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "path": { "type": "string" },
          "type": { "enum": ["view", "viewmodel", "model"] }
        }
      }
    }
  },
  "required": ["success"]
}

Generated SwiftUI View Example

// ContentView.swift
import SwiftUI

struct ContentView: View {
    @StateObject private var viewModel = ContentViewModel()
    @State private var searchText = ""
    @State private var isShowingSettings = false

    var body: some View {
        NavigationSplitView {
            // Sidebar
            SidebarView(selection: $viewModel.selectedCategory)
        } detail: {
            // Detail view
            if let category = viewModel.selectedCategory {
                CategoryDetailView(category: category)
            } else {
                Text("Select a category")
                    .foregroundStyle(.secondary)
            }
        }
        .searchable(text: $searchText, prompt: "Search items...")
        .onChange(of: searchText) { _, newValue in
            viewModel.search(query: newValue)
        }
        .toolbar {
            ToolbarItemGroup {
                Button(action: viewModel.refresh) {
                    Label("Refresh", systemImage: "arrow.clockwise")
                }

                Button(action: { isShowingSettings = true }) {
                    Label("Settings", systemImage: "gear")
                }
            }
        }
        .sheet(isPresented: $isShowingSettings) {
            SettingsView()
        }
        .task {
            await viewModel.loadData()
        }
    }
}

// MARK: - Preview
#Preview {
    ContentView()
}

#Preview("With Data") {
    ContentView()
        .environmentObject(PreviewData.sampleViewModel)
}

ViewModel

// ContentViewModel.swift
import SwiftUI
import Combine

@MainActor
class ContentViewModel: ObservableObject {
    @Published var items: [Item] = []
    @Published var selectedCategory: Category?
    @Published var isLoading = false
    @Published var errorMessage: String?

    private let dataService: DataService
    private var cancellables = Set<AnyCancellable>()

    init(dataService: DataService = .shared) {
        self.dataService = dataService
    }

    func loadData() async {
        isLoading = true
        errorMessage = nil

        do {
            items = try await dataService.fetchItems()
        } catch {
            errorMessage = error.localizedDescription
        }

        isLoading = false
    }

    func search(query: String) {
        // Debounced search implementation
        Task {
            try? await Task.sleep(nanoseconds: 300_000_000)
            // Perform search
        }
    }

    func refresh() {
        Task {
            await loadData()
        }
    }
}

Reusable Component

// ItemRowView.swift
import SwiftUI

struct ItemRowView: View {
    let item: Item
    @Binding var isSelected: Bool
    var onDelete: (() -> Void)?

    var body: some View {
        HStack {
            Image(systemName: item.icon)
                .foregroundStyle(item.color)
                .frame(width: 24, height: 24)

            VStack(alignment: .leading, spacing: 4) {
                Text(item.title)
                    .font(.headline)

                Text(item.subtitle)
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
            }

            Spacer()

            if isSelected {
                Image(systemName: "checkmark")
                    .foregroundStyle(.blue)
            }
        }
        .padding(.vertical, 4)
        .contentShape(Rectangle())
        .onTapGesture {
            isSelected.toggle()
        }
        .contextMenu {
            Button("Edit") { }
            Button("Duplicate") { }
            Divider()
            Button("Delete", role: .destructive) {
                onDelete?()
            }
        }
    }
}

Settings View (macOS)

// SettingsView.swift
import SwiftUI

struct SettingsView: View {
    var body: some View {
        TabView {
            GeneralSettingsView()
                .tabItem {
                    Label("General", systemImage: "gear")
                }

            AppearanceSettingsView()
                .tabItem {
                    Label("Appearance", systemImage: "paintpalette")
                }

            AdvancedSettingsView()
                .tabItem {
                    Label("Advanced", systemImage: "slider.horizontal.3")
                }
        }
        .frame(width: 500, height: 400)
    }
}

struct GeneralSettingsView: View {
    @AppStorage("launchAtLogin") private var launchAtLogin = false
    @AppStorage("checkForUpdates") private var checkForUpdates = true

    var body: some View {
        Form {
            Toggle("Launch at Login", isOn: $launchAtLogin)
            Toggle("Check for Updates Automatically", isOn: $checkForUpdates)
        }
        .formStyle(.grouped)
        .padding()
    }
}

List View with Selection

// ItemListView.swift
import SwiftUI

struct ItemListView: View {
    @ObservedObject var viewModel: ItemListViewModel
    @State private var selection: Set<Item.ID> = []
    @State private var sortOrder = [KeyPathComparator(\Item.name)]

    var body: some View {
        Table(viewModel.items, selection: $selection, sortOrder: $sortOrder) {
            TableColumn("Name", value: \.name)
            TableColumn("Type", value: \.type)
            TableColumn("Modified", value: \.modifiedDate) { item in
                Text(item.modifiedDate, style: .date)
            }
            TableColumn("Size") { item in
                Text(ByteCountFormatter.string(fromByteCount: item.size, countStyle: .file))
            }
            .width(80)
        }
        .onChange(of: sortOrder) { _, newOrder in
            viewModel.sort(by: newOrder)
        }
        .contextMenu(forSelectionType: Item.ID.self) { items in
            Button("Open") { viewModel.open(items) }
            Button("Delete", role: .destructive) { viewModel.delete(items) }
        } primaryAction: { items in
            viewModel.open(items)
        }
    }
}

State Management Patterns

@State - Local state

@State private var isExpanded = false
@State private var selectedTab = 0

@Binding - Two-way binding from parent

@Binding var isPresented: Bool
@Binding var selectedItem: Item?

@StateObject - Owned observable object

@StateObject private var viewModel = MyViewModel()

@ObservedObject - Passed observable object

@ObservedObject var viewModel: MyViewModel

@EnvironmentObject - Shared via environment

@EnvironmentObject var settings: AppSettings

@AppStorage - UserDefaults backed

@AppStorage("username") private var username = ""

Best Practices

  1. Use @StateObject for ownership: When the view creates the object
  2. Use @ObservedObject for injection: When the object is passed in
  3. Keep views small: Extract components
  4. Use previews: Test different states
  5. Mark async operations: Use @MainActor for ViewModels
  6. Handle errors gracefully: Show user-friendly messages

Related Skills

  • macos-entitlements-generator - App capabilities
  • macos-notarization-workflow - Distribution
  • xctest-ui-test-generator - UI testing

Related Agents

  • swiftui-macos-expert - SwiftUI expertise
  • desktop-ux-analyst - UX patterns

Du fichier au premier essai

Le téléchargement contient exactement le contenu affiché sur cette fiche. Cette copie peut différer de la dernière version du dépôt source.

Consulter la source et ses fichiers annexes

Ce téléchargement contient uniquement SKILL.md. Les scripts, références, modèles et dépendances éventuels ne sont pas inclus. Récupérez les fichiers nécessaires depuis la source en conservant leur arborescence avant de poursuivre.

1. Télécharger le fichier

Télécharger SKILL.md

Depuis la racine d’un projet de test, enregistrez le fichier sous .skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md, ou utilisez la commande suivante. Ce dossier sert à examiner la skill avant son installation.

Commande pour macOS/Linux ou WSL : un shell POSIX et curl sont nécessaires. Sous Windows sans WSL, utilisez le bouton de téléchargement et créez le dossier manuellement.

mkdir -p '.skill-downloads/swiftui-view-generator-mmlj2o7o' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/swiftui-view-generator-mmlj2o7o/download' --output '.skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md.part' && mv '.skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md.part' '.skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md'

2. Vérifier les prérequis

Lisez SKILL.md avant de l’utiliser. Si le fichier cite des scripts ou services externes, examinez-les et préparez les accès nécessaires dans votre environnement de test.

Outils déclarés par l’auteur (à vérifier dans votre agent) : Read, Write, Edit, Bash, Glob, Grep

Aucune section de prérequis reconnue dans ce fichier. Cela ne signifie pas qu’il est autonome : les bibliothèques, outils et accès peuvent être cités ailleurs dans le contenu ou dans le dépôt source.

Les plateformes de la fiche sont des indications du catalogue. Les chemins ci-dessous suivent la documentation des outils ; ils ne prouvent pas que cette skill y a été exécutée. Aucune version minimale de ces outils n’est attestée pour cette fiche.

3. Charger la skill

Après vérification, copiez le dossier complet dans le projet avec l’une des commandes ci-dessous, puis ouvrez une nouvelle session de l’outil. La commande s’arrête si un dossier du même nom existe déjà : comparez les fichiers avant de le remplacer.

Claude Code
test -f '.skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md' && test -s '.skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/swiftui-view-generator' && cp -R '.skill-downloads/swiftui-view-generator-mmlj2o7o' '.claude/skills/swiftui-view-generator'

OpenSkills

OpenSkills doit déjà être installé. La procédure locale install/read est contrôlée avec OpenSkills 1.5.0, qui exige Node.js ≥ 20.6.0. Aucun slug du catalogue n’est résolu automatiquement.

Installation officielle d’OpenSkills
openskills install './.skill-downloads/swiftui-view-generator-mmlj2o7o'

openskills read 'swiftui-view-generator-mmlj2o7o'

La lecture doit afficher le contenu du fichier installé et son dossier de base. Elle ne lance ni la skill ni ses dépendances.

Pour un agent qui lit AGENTS.md, synchronisez ensuite l’index. Cette commande modifie AGENTS.md : relisez le diff avant de l’utiliser.

openskills sync

Mode manuel ou autre outil : joignez SKILL.md à une conversation, ou ouvrez-le dans un agent capable de lire les fichiers. Ajoutez les ressources annexes nécessaires. Il n’existe pas de dossier universel reconnu par tous les outils.

4. Faire un premier essai

Utilisez une entrée courte et fictive : un endpoint d’API, un petit document ou un brief d’interface. Dans une nouvelle conversation, joignez le fichier ou donnez son chemin à l’agent, puis adaptez cette demande :

Lis .skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md et applique ses instructions à cet exemple : [décrire une entrée de test]. Indique les fichiers, dépendances ou accès qui manquent. Produis le résultat demandé par la skill sans inventer de données ni exécuter de script non examiné.

Résultat attendu : une sortie correspondant aux instructions de la skill, ou une liste précise des prérequis manquants. Une simple confirmation de lecture ne valide pas le premier usage. Si une ressource externe est indisponible, ce parcours reste à tester.

Skills similaires