Back to Mobile Development

swiftui-view-refactor

SwiftUIiOSrefactoringcode qualitybest practicesdependency injectionObservationview architecture
3.7k📄 MIT🕒 2026-03-29Source ↗

Install this skill

npx skills add dimillian/skills

Works across Claude Code, Cursor, Codex, Copilot & Antigravity

The swiftui-view-refactor skill standardizes SwiftUI architecture by enforcing strict structural, dependency, and composition rules. It moves beyond generic cleanup, prioritizing a consistent property ordering—from environment values down to view body—and modularizing bloated components. By favoring a direct Model-View relationship, it discourages unnecessary abstraction layers like bloated view models, instead promoting small subviews and functional state orchestration via @State and @Environment. When files grow past 300 lines, this skill mandates logical separation through extensions and marked regions. It ensures that business logic remains decoupled from view representation, resulting in cleaner, more maintainable code that aligns with modern Swift Observation practices. The focus remains on readability and predictability, transforming cluttered, inconsistent views into highly modular components that prioritize native SwiftUI patterns over architectural boilerplate.

When to Use This Skill

  • Cleaning up views that have grown unreadable or exceed 300 lines of code
  • Replacing legacy, complex view-model patterns with native SwiftUI state orchestration
  • Improving code review consistency across a team's view layer
  • Extracting complex UI sections into smaller, testable sub-components

How to Invoke This Skill

Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:

  • refactor this view to match SwiftUI best practices
  • clean up this bloated SwiftUI file structure
  • split this large SwiftUI body into smaller subviews
  • convert this view model to use proper dependency injection in init
  • organize this SwiftUI file using mark extensions

Pro Tips

  • 💡Always run this skill after initial view development to catch structural inconsistencies early, before they become deeply ingrained.
  • 💡Combine this skill with a Swift linter to enforce both structural best practices and granular Swift style guidelines simultaneously.
  • 💡Prioritize injecting shared models and services via `@Environment` or direct parameters to keep views small and highly composable, strictly adhering to the MV pattern.

What this skill does

  • Enforces standardized property and method ordering within SwiftUI structs
  • Refactors monolithic bodies into granular, reusable subviews or computed properties
  • Optimizes memory by initializing non-optional view models via dependency injection
  • Organizes large view files using marked extensions for actions and helpers
  • Aligns state management with native Observable patterns

When not to use it

  • When a view requires minimal logic and is already under 50 lines
  • If the project strictly mandates an MVVM architecture that forbids raw state orchestration

Example workflow

  1. Analyze the current struct properties and rearrange them to follow the defined ordering standard
  2. Evaluate large view bodies and identify logical sections suitable for extraction into subviews
  3. Move isolated helper functions and action logic into private extensions with marked headers
  4. Replace optional or non-initialized view models with direct, dependency-injected properties
  5. Verify that state management uses @State or @Environment correctly without redundant wrappers

Prerequisites

  • Existing SwiftUI code
  • Understanding of the @Observable macro
  • Basic knowledge of dependency injection

Pitfalls & limitations

  • !Over-extracting tiny views that increase boilerplate without improving clarity
  • !Moving logic into extensions that breaks access to private view state
  • !Ignoring the specific ordering rules which can lead to inconsistent diffs in version control

FAQ

Should I always use a view model for complex views?
No. The skill emphasizes that views should be lightweight. Only introduce a view model if the logic is too complex for simple @State or @Environment orchestration.
When is it better to use a computed view property instead of a new struct?
Use a computed property when the view is small and lacks complex state. If the component grows or needs to be reused elsewhere, promote it to a dedicated struct.
How should I handle large files that aren't quite 300 lines?
Apply the ordering rules first. If the file remains difficult to navigate, use markers to group your logic even if it is below the 300-line threshold.

How it compares

Unlike manual refactoring which is prone to inconsistency, this skill forces strict adherence to a documented architecture, ensuring every view in the project follows an identical structural pattern.

Source & trust

3.7k stars📄 MIT🕒 Updated 2026-03-29
📄 Full skill instructions — original source: dimillian/skills
# SwiftUI View Refactor

## Overview
Apply a consistent structure and dependency pattern to SwiftUI views, with a focus on ordering, Model-View (MV) patterns, careful view model handling, and correct Observation usage.

## Core Guidelines

### 1) View ordering (top → bottom)
- Environment
- private/public let
- @State / other stored properties
- computed var (non-view)
- init
- body
- computed view builders / other view helpers
- helper / async functions

### 2) Prefer MV (Model-View) patterns
- Default to MV: Views are lightweight state expressions; models/services own business logic.
- Favor @State, @Environment, @Query, and task/onChange for orchestration.
- Inject services and shared models via @Environment; keep views small and composable.
- Split large views into subviews rather than introducing a view model.

### 3) Split large bodies and view properties
- If body grows beyond a screen or has multiple logical sections, split it into smaller subviews.
- Extract large computed view properties (var header: some View { ... }) into dedicated View types when they carry state or complex branching.
- It's fine to keep related subviews as computed view properties in the same file; extract to a standalone View struct only when it structurally makes sense or when reuse is intended.
- Prefer passing small inputs (data, bindings, callbacks) over reusing the entire parent view state.

Example (extracting a section):

var body: some View {
VStack(alignment: .leading, spacing: 16) {
HeaderSection(title: title, isPinned: isPinned)
DetailsSection(details: details)
ActionsSection(onSave: onSave, onCancel: onCancel)
}
}


Example (long body → shorter body + computed views in the same file):

var body: some View {
List {
header
filters
results
footer
}
}

private var header: some View {
VStack(alignment: .leading, spacing: 6) {
Text(title).font(.title2)
Text(subtitle).font(.subheadline)
}
}

private var filters: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(filterOptions, id: \.self) { option in
FilterChip(option: option, isSelected: option == selectedFilter)
.onTapGesture { selectedFilter = option }
}
}
}
}


Example (extracting a complex computed view):

private var header: some View {
HeaderSection(title: title, subtitle: subtitle, status: status)
}

private struct HeaderSection: View {
let title: String
let subtitle: String?
let status: Status

var body: some View {
VStack(alignment: .leading, spacing: 4) {
Text(title).font(.headline)
if let subtitle { Text(subtitle).font(.subheadline) }
StatusBadge(status: status)
}
}
}


### 4) View model handling (only if already present)
- Do not introduce a view model unless the request or existing code clearly calls for one.
- If a view model exists, make it non-optional when possible.
- Pass dependencies to the view via init, then pass them into the view model in the view's init.
- Avoid bootstrapIfNeeded patterns.

Example (Observation-based):

@State private var viewModel: SomeViewModel

init(dependency: Dependency) {
_viewModel = State(initialValue: SomeViewModel(dependency: dependency))
}


### 5) Observation usage
- For @Observable reference types, store them as @State in the root view.
- Pass observables down explicitly as needed; avoid optional state unless required.

## Workflow

1) Reorder the view to match the ordering rules.
2) Favor MV: move lightweight orchestration into the view using @State, @Environment, @Query, task, and onChange.
3) If a view model exists, replace optional view models with a non-optional @State view model initialized in init by passing dependencies from the view.
4) Confirm Observation usage: @State for root @Observable view models, no redundant wrappers.
5) Keep behavior intact: do not change layout or business logic unless requested.

## Notes

- Prefer small, explicit helpers over large conditional blocks.
- Keep computed view builders below body and non-view computed vars above init.
- For MV-first guidance and rationale, see references/mv-patterns.md.

## Large-view handling

- When a SwiftUI view file exceeds ~300 lines, split it using extensions to group related helpers. Move async functions and helper functions into dedicated private extensions, separated with // MARK: - comments that describe their purpose (e.g., // MARK: - Actions, // MARK: - Subviews, // MARK: - Helpers). Keep the main struct focused on stored properties, init, and body, with view-building computed vars also grouped via marks when the file is long.

How to Use This Skill Unit

Option A: Project-Specific (Recommended)

  1. Click "Download" above
  2. In your project, create the directory: .agent/skills/swiftui-view-refactor/
  3. Save the file as SKILL.md
  4. The agent will automatically discover the skill based on its description.

Option B: Global Installation (All Agents)

Save the file to these locations to make it available across all projects:

  • Claude Code: ~/.claude/skills/dimillian/skills/swiftui-view-refactor/SKILL.md
  • Cursor: ~/.cursor/skills/dimillian/skills/swiftui-view-refactor/SKILL.md
  • Antigravity: ~/.gemini/antigravity/skills/dimillian/skills/swiftui-view-refactor/SKILL.md

🚀 Install with CLI:
npx skills add dimillian/skills

Read the Master Guide: Mastering Agent Skills

Recommended Rules

View more rules

Recommended Workflows

View more workflows

Recommended MCP Servers

View more MCP servers

Take It Further

Maximize your productivity with these powerful resources

📋

Define Your Standards

Set up coding standards to ensure this workflow produces consistent, high-quality results.

Browse Rules Library
📖

Master Workflows

Learn how to create custom workflows, use Turbo Mode, and build your automation library.

Complete Guide

How to use this Skill in Claude Code & Cursor

For Claude Code (CLI)

To use this skill in Claude Code, copy the rule content into your project's custom instructions or follow our Add-Skill CLI guide. This ensures Claude follows your standards during every code generation.

For Cursor & Windsurf

For Cursor or Windsurf, individual skills are best used in the "Rules for AI" section. This specific unit helps the agent avoid mobile development issues, leading to cleaner, more efficient code.

Why the skill format matters: the standardized Agent Skills format lets your AI agent load detailed instructions only when they are relevant, keeping your prompt clean while improving results.

Source & attribution

This skill is categorized under Mobile Development and is published by Thomas Ricouard, maintained in dimillian/skills.

← Browse All Agent Skills
Sponsored AI assistant. Recommendations may be paid.