Generates structured SwiftUI Views and ViewModels using the MVVM pattern. It handles file scaffolding and standard navigation requirements for iOS 15+ apps.

Install

mkdir -p .claude/skills/view && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/10114" && unzip -o skill.zip -d .claude/skills/view && rm skill.zip

Installs to .claude/skills/view

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Cria uma nova View SwiftUI seguindo o padrao MVVM do projeto (iOS 15+). Use quando o usuario pedir para criar uma nova tela, view ou screen.
140 charsno explicit “when” trigger
Intermediate

Key capabilities

  • Create SwiftUI views
  • Scaffold ViewModels
  • Integrate repositories
  • Standardize UI components
  • Implement MVVM pattern

How it works

It generates a SwiftUI view and ViewModel pair following the MVVM pattern, including state management and repository injection.

Inputs & outputs

You give it
View name
You get back
SwiftUI View and ViewModel

When to use view

  • Creating a new screen for an iOS application
  • Scaffolding a view with a dedicated ViewModel
  • Standardizing UI components within an MVVM codebase

About this skill

Crie uma nova View SwiftUI seguindo o padrao MVVM do projeto. Target minimo: iOS 15.

Argumentos

Nome da View em PascalCase: $ARGUMENTS

Se $ARGUMENTS estiver vazio, pergunte: "Qual o nome da View? (ex: ProductDetail, Profile)"

A partir do nome PascalCase, derive:

  • <Name>View para o nome da struct da View
  • <Name>ViewModel para o nome da classe do ViewModel
  • Diretorio: Views/<Name>/

Perguntas a fazer (se nao informadas nos argumentos)

  1. ViewModel dedicado: precisa de ViewModel? (padrao: sim)
  2. Repository: qual Repository sera injetado no ViewModel? (ex: UserRepository) — se nao souber, use um placeholder
  3. Navegacao: a View sera usada dentro de um NavigationView? (padrao: sim). Se nao, omita o wrapper NavigationView, .navigationViewStyle(.stack) e o .navigationTitle.

O que criar

1. Views/<Name>/<Name>View.swift

Para suportar previews com estados diferentes, use o init com StateObject injetavel:

import SwiftUI

struct <Name>View: View {

    @StateObject private var viewModel: <Name>ViewModel

    init(viewModel: <Name>ViewModel = <Name>ViewModel()) {
        _viewModel = StateObject(wrappedValue: viewModel)
    }

    var body: some View {
        NavigationView {
            Group {
                switch viewModel.state {
                case .idle:
                    EmptyView()

                case .loading:
                    ProgressView("Carregando...")

                case .success(let data):
                    content(data)

                case .error(let message):
                    ErrorStateView(message: message) {
                        Task { await viewModel.load() }
                    }
                }
            }
            .navigationTitle("<Name>")
        }
        .navigationViewStyle(.stack)
        .task {
            await viewModel.load()
        }
    }

    // MARK: - Subviews

    private func content(_ data: <DataType>) -> some View {
        ScrollView {
            VStack(spacing: 16) {
                // TODO: Adicione o conteudo aqui
            }
            .padding()
        }
    }
}

// MARK: - Preview

#Preview {
    <Name>View()
}

#Preview("Loading") {
    <Name>View(viewModel: <Name>ViewModel(repository: Mock<Repository>(state: .loading)))
}

#Preview("Error") {
    <Name>View(viewModel: <Name>ViewModel(repository: Mock<Repository>(state: .failure)))
}

2. ViewModels/<Name>ViewModel.swift (se solicitado)

Para padrões completos de ViewModel (busca, paginação, múltiplos estados), use a skill view-model.

import Foundation

@MainActor
final class <Name>ViewModel: ObservableObject {

    // MARK: - State

    @Published private(set) var state: ViewState<<DataType>> = .idle

    // MARK: - Dependencies

    private let repository: <Repository>Protocol

    // MARK: - Init

    init(repository: <Repository>Protocol = <Repository>()) {
        self.repository = repository
    }

    // MARK: - Actions

    func load() async {
        state = .loading

        do {
            let data = try await repository.fetch()
            state = .success(data)
        } catch {
            state = .error(error.localizedDescription)
        }
    }
}

3. Views/<Name>/Components/ (diretorio)

Crie o diretorio para componentes futuros da View. Nao crie arquivos dentro dele, apenas informe o usuario que subcomponentes devem ser colocados aqui.

Apos criar os arquivos

Informe o usuario que ainda precisa:

  1. Verificar se Utilities/ViewState.swift existe no projeto — se nao, crie-o
  2. Verificar se Views/Shared/ErrorStateView.swift existe no projeto — se nao, crie o arquivo com o codigo abaixo:
import SwiftUI

struct ErrorStateView: View {

    let message: String
    let retryAction: () -> Void

    var body: some View {
        VStack(spacing: 16) {
            Image(systemName: "exclamationmark.triangle")
                .font(.system(size: 48))
                .foregroundColor(.secondary)

            Text(message)
                .font(.body)
                .multilineTextAlignment(.center)
                .foregroundColor(.secondary)

            Button(action: retryAction) {
                Text("Tentar novamente")
                    .fontWeight(.medium)
            }
            .buttonStyle(.bordered)
        }
        .padding()
    }
}
  1. Criar o Repository correspondente em Repositories/ (se ainda nao existir), seguindo o padrao Protocol + implementacao concreta
  2. Adicionar a rota no AppRouter se estiver usando navegacao centralizada

Regras

View

  • Structs que conformam com View — nunca classes
  • Declarativas e enxutas — sem logica de negocio no body
  • Extraia subviews privadas quando o body ultrapassar ~40 linhas
  • Use @State para estado local da View (toggle, campo de texto)
  • Use @StateObject para criar o ViewModel, @ObservedObject para receber de fora
  • Prefira .task {} para chamadas async ao aparecer a View
  • Use switch sobre o ViewState para reagir a cada estado
  • Use NavigationView + .navigationViewStyle(.stack) — nunca NavigationStack (requer iOS 16)
  • Use NavigationLink(destination:) — nunca NavigationLink(value:) (requer iOS 16)
  • Toda View deve ter um #Preview funcional

ViewModel

  • Nunca importar SwiftUI — apenas Foundation e Combine
  • Conforma com ObservableObject — nunca @Observable (requer iOS 17)
  • Marcado como @MainActor
  • Usa ViewState<T> para gerenciar estado — nunca booleans avulsos
  • Propriedades de estado usam @Published private(set)
  • Dependencias injetadas via init (para testabilidade)
  • Metodos publicos representam acoes do usuario

Nomenclatura

TipoConvencaoExemplo
ViewPascalCase + sufixo ViewProductDetailView
ViewModelPascalCase + sufixo ViewModelProductDetailViewModel
ComponentePascalCase + sufixo ViewProductCardView
DiretorioPascalCase (nome da feature)Views/ProductDetail/

APIs proibidas (acima do iOS 15)

NAO usarRequerUsar no lugar
@ObservableiOS 17ObservableObject + @Published
@State com classiOS 17@StateObject
@BindableiOS 17@ObservedObject
NavigationStackiOS 16NavigationView + .navigationViewStyle(.stack)
NavigationLink(value:)iOS 16NavigationLink(destination:)
navigationDestination(for:)iOS 16Remover
ContentUnavailableViewiOS 17ErrorStateView customizada
.environment() com ObservableiOS 17@EnvironmentObject

Geral

  • Nenhum import SwiftUI fora de Views
  • async/await para concorrencia — prefira sobre Combine para novas features
  • Dependency Inversion — ViewModels dependem de protocolos, nao de implementacoes concretas
  • Unidirectional Data Flow — View observa ViewModel, ViewModel atualiza estado, View re-renderiza

Checklist de Revisao

  • Struct conforma com View (nunca class)
  • Sem logica de negocio no body
  • @StateObject com init injetavel para suportar previews
  • Subviews extraidas quando body > 40 linhas
  • switch exaustivo sobre ViewState (todos os 4 casos tratados)
  • .task {} usado para carregamento async (nao onAppear)
  • NavigationView + .navigationViewStyle(.stack) (nunca NavigationStack)
  • NavigationLink(destination:) (nunca NavigationLink(value:))
  • ErrorStateView presente em Views/Shared/
  • ViewState.swift presente em Utilities/
  • #Preview funcional com pelo menos estado de sucesso
  • Diretorio Components/ criado para subcomponentes futuros

When not to use it

  • Non-SwiftUI projects

Prerequisites

iOS 15+

Limitations

  • Requires iOS 15+

How it compares

It enforces a strict MVVM architecture for iOS development, ensuring consistency and testability.

Compared to similar skills

view side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
view (this skill)04moNo flagsIntermediate
swiftui-expert-skill134moNo flagsIntermediate
swiftui-ui-patterns15moNo flagsIntermediate
ios-navigation23moNo flagsIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

Search skills

Search the agent skills registry