swiftui-view-refactor
Skill20 starsChanged 2 months agoMITView on GitHub
Refactor and review SwiftUI view files with strong defaults for small dedicated subviews, MV-over-MVVM data flow, stable view trees, explicit dependency injection, and correct Observation usage. Use when cleaning up a SwiftUI view, splitting long bodies, removing inline actions or side effects, reducing computed `some View` helpers, or standardizing `@Observable` and view model initialization patterns.
17 other projects use a version of this, 17 of them edited.
Adopted by
Most recently taken up by
- MMACABRE/SKILLSedited, first seen Nov 8, 2026
- tornikegomareli/Skillsedited, first seen Nov 8, 2026
- VelimirMueller/claude-skillsedited, first seen Nov 1, 2026
- VelimirMueller/ai-development-skillsedited, first seen Nov 1, 2026
- steipete/agent-scriptsedited, first seen Oct 20, 2026
- spokvulcan/claude-code-build-ios-appsedited, first seen Oct 17, 2026
Used with
Projects with it also use swift-concurrency-expert, gh-issue-fix-flow and 4 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
eugenepyvovarovSkillswift-concurrency-expert
Swift Concurrency review and remediation for Swift 6.2+. Use when asked to review Swift Concurrency usage, improve concurrency compliance, or fix Swift concurrency compiler errors in a feature or file.
Also in 9 projects that use this
ParkerRexSkillgh-issue-fix-flow
End-to-end GitHub issue fix workflow using gh, local code changes, builds/tests, and git push. Use when asked to take an issue number, inspect the issue via gh, implement a fix, run XcodeBuildMCP builds/tests, commit with a closing message, and push.
Also in 3 projects that use this
patrickserranoSkillapp-store-changelog
Create user-facing App Store release notes from git history. Use when asked to generate release changelog, App Store "What's New" text, or release notes based on git tags.
Also in 4 projects that use this
jamesrochabrunSkillswift-concurrency
Guide for building, auditing, and refactoring Swift code using modern concurrency patterns (Swift 6+). This skill should be used when working with async/await, Tasks, actors, MainActor, Sendable types, isolation domains, or when migrating legacy callback/Combine code to structured concurrency. Covers Approachable Concurrency settings, isolated parameters, and common pitfalls.
Also in 4 projects that use this
xfstudioSkillswiftui-expert-skill
Write, review, or improve SwiftUI code following best practices for state management, view composition, performance, modern APIs, Swift concurrency, and iOS 26+ Liquid Glass adoption. Use when building new SwiftUI features, refactoring existing views, reviewing code quality, or adopting modern SwiftUI patterns.
Also in 3 projects that use this
kingsidharthSkillswiftui-pro
Comprehensively reviews SwiftUI code for best practices on modern APIs, maintainability, and performance. Use when reading, writing, or reviewing SwiftUI projects.
Also in 3 projects that use this
Other versions17 projects use a version of this.
Word for word · 0
None found.
Edited · 17
- openai/plugins★ 7.8k94% same
- steipete/agent-scripts★ 7.4k33% same
- Dimillian/Skills★ 4k99% same
- AFK-surf/OpenBridge★ 43034% same
- omarshahine/HomeClaw★ 19196% same
- robinebers/skills★ 4894% same
- eugenepyvovarov/mcpbundler-agent-skills-marketplace★ 1234% same
- VelimirMueller/ai-development-skills★ 798% same
- VelimirMueller/claude-skills★ 798% same
- Adhamxon/claude-code-skills★ 299% same
7 more not listed
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository16 other files it gives its agents.
- AGENTS.mdAGENTS.md
- code-reviewSkill
- gemini-files-apiSkill
- harness-engineeringSkill
- hint-overlay-visual-verificationSkill
- ios-xcodegenSkill
- lifecycle-and-side-effects-correctnessSkill
- local-model-servingSkill
- mechanism-auditSkill
- meeting-transcriptionSkill
- public-source-release-auditSkill
- silent-pushes-setupSkill
- spec-creation-updatingSkill
- swift-testingSkill
- xcode-buildSkill
- xcode-cloudSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
21 rules. 9 are common, 0 are distinctive, and 12 are very specific to this project.
9
Common
Most of the 17 edited versions we read keep these.
0
Distinctive
This author's own choices. Worth a look.
12
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Common: line 28
Do not introduce a view model just to mirror local view state or wrap environment dependencies.
- Common: line 29
If a screen is getting large, split the UI into subviews before inventing a new view model layer.
- Very specific: line 33
Prefer extracting dedicated View types for non-trivial sections, especially when they have state, async work, branching, or deserve their …
- Very specific: line 34
Keep computed some View helpers rare and small.
- Common: line 36
If an extracted subview becomes reusable or independently meaningful, move it to its own file.
- Common: line 103
Do not keep non-trivial button actions inline in the view body.
- Very specific: line 104
Do not bury business logic inside .task, .onAppear, .onChange, or .refreshable.
- Common: line 105
Prefer calling small private methods from the view, and move real business logic into services/models.
- Very specific: line 131
Avoid body or computed views that return completely different root branches via if/else.
- Very specific: line 132
Prefer a single stable base view with conditions inside sections/modifiers (overlay, opacity, disabled, toolbar, etc.).
- Common: line 163
Treat view models as a legacy or explicit-need pattern, not the default.
- Common: line 164
Do not introduce a view model unless the request or existing code clearly calls for one.
- Common: line 165
If a view model exists, make it non-optional when possible.
- Very specific: line 167
Avoid bootstrapIfNeeded patterns and other delayed setup workarounds.
- Very specific: line 182
If the deployment target includes iOS 16 or earlier, use @StateObject at the owner and @ObservedObject when injecting legacy observable …
- Very specific: line 187
Remove inline actions and side effects from body.
- Very specific: line 189
Ensure stable view structure: avoid top-level if-based branch swapping.
- Very specific: line 190
If a view model exists or is explicitly required, replace optional view models with a non-optional @State view model initialized in init.
- Common: line 192
Keep behavior intact: do not change layout or business logic unless requested.
- Very specific: line 196
Prefer small, explicit view types over large conditional blocks and large computed some View properties.
- Very specific: line 197
Keep computed view builders below body and non-view computed vars above init.
“Common” is measured: kept by at least 6 in 10 of the 17 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
SwiftUI View Refactor
Overview
Refactor SwiftUI views toward small, explicit, stable view types. Default to vanilla SwiftUI: local state in the view, shared dependencies in the environment, business logic in services/models, and view models only when the request or existing code clearly requires one.
Core Guidelines
1) View ordering (top → bottom)
- Enforce this ordering unless the existing file has a stronger local convention you must preserve.
- Environment
private/publiclet@State/ other stored properties- computed
var(non-view) initbody- computed view builders / other view helpers
- helper / async functions
2) Default to MV, not MVVM
- Views should be lightweight state expressions and orchestration points, not containers for business logic.
- Favor
@State,@Environment,@Query,.task,.task(id:), andonChangebefore reaching for a view model. - Inject services and shared models via
@Environment; keep domain logic in services/models, not in the view body. - Do not introduce a view model just to mirror local view state or wrap environment dependencies.
- If a screen is getting large, split the UI into subviews before inventing a new view model layer.
3) Strongly prefer dedicated subview types over computed some View helpers
- Flag
bodyproperties that are longer than roughly one screen or contain multiple logical sections. - Prefer extracting dedicated
Viewtypes for non-trivial sections, especially when they have state, async work, branching, or deserve their own preview. - Keep computed
some Viewhelpers rare and small. Do not build an entire screen out ofprivate var header: some View-style fragments. - Pass small, explicit inputs (data, bindings, callbacks) into extracted subviews instead of handing down the entire parent state.
- If an extracted subview becomes reusable or independently meaningful, move it to its own file.
Prefer:
var body: some View {
List {
HeaderSection(title: title, subtitle: subtitle)
FilterSection(
filterOptions: filterOptions,
selectedFilter: $selectedFilter
)
ResultsSection(items: filteredItems)
FooterSection()
}
}
private struct HeaderSection: View {
let title: String
let subtitle: String
var body: some View {
VStack(alignment: .leading, spacing: 6) {
Text(title).font(.title2)
Text(subtitle).font(.subheadline)
}
}
}
private struct FilterSection: View {
let filterOptions: [FilterOption]
@Binding var selectedFilter: FilterOption
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(filterOptions, id: \.self) { option in
FilterChip(option: option, isSelected: option == selectedFilter)
.onTapGesture { selectedFilter = option }
}
}
}
}
}Avoid:
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)
}
}3b) Extract actions and side effects out of body
- Do not keep non-trivial button actions inline in the view body.
- Do not bury business logic inside
.task,.onAppear,.onChange, or.refreshable. - Prefer calling small private methods from the view, and move real business logic into services/models.
- The body should read like UI, not like a view controller.
- For analytics, purchase, retry, cancellation, or other lifecycle side effects, use
lifecycle-and-side-effects-correctness; this refactor skill only keeps the view structure legible.
Button("Save", action: save)
.disabled(isSaving)
.task(id: searchText) {
await reload(for: searchText)
}
private func save() {
Task { await saveAsync() }
}
private func reload(for searchText: String) async {
guard !searchText.isEmpty else {
results = []
return
}
await searchService.search(searchText)
}4) Keep a stable view tree (avoid top-level conditional view swapping)
- Avoid
bodyor computed views that return completely different root branches viaif/else. - Prefer a single stable base view with conditions inside sections/modifiers (
overlay,opacity,disabled,toolbar, etc.). - Root-level branch swapping causes identity churn, broader invalidation, and extra recomputation.
Prefer:
var body: some View {
List {
documentsListContent
}
.toolbar {
if canEdit {
editToolbar
}
}
}Avoid:
var documentsListView: some View {
if canEdit {
editableDocumentsList
} else {
readOnlyDocumentsList
}
}5) View model handling (only if already present or explicitly requested)
- Treat view models as a legacy or explicit-need pattern, not the default.
- 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 create the view model in the view'sinit. - Avoid
bootstrapIfNeededpatterns and other delayed setup workarounds.
Example (Observation-based):
@State private var viewModel: SomeViewModel
init(dependency: Dependency) {
_viewModel = State(initialValue: SomeViewModel(dependency: dependency))
}6) Observation usage
- For
@Observablereference types on iOS 17+, store them as@Statein the owning view. - Pass observables down explicitly; avoid optional state unless the UI genuinely needs it.
- If the deployment target includes iOS 16 or earlier, use
@StateObjectat the owner and@ObservedObjectwhen injecting legacy observable models.
Workflow
- Reorder the view to match the ordering rules.
- Remove inline actions and side effects from
body; move business logic into services/models and keep only thin orchestration in the view. - Shorten long bodies by extracting dedicated subview types; avoid rebuilding the screen out of many computed
some Viewhelpers. - Ensure stable view structure: avoid top-level
if-based branch swapping; move conditions to localized sections/modifiers. - If a view model exists or is explicitly required, replace optional view models with a non-optional
@Stateview model initialized ininit. - Confirm Observation usage:
@Statefor root@Observablemodels on iOS 17+, legacy wrappers only when the deployment target requires them. - Keep behavior intact: do not change layout or business logic unless requested.
Notes
- Prefer small, explicit view types over large conditional blocks and large computed
some Viewproperties. - Keep computed view builders below
bodyand non-view computed vars aboveinit. - A good SwiftUI refactor should make the view read top-to-bottom as data flow plus layout, not as mixed layout and imperative logic.
- Stable view trees reduce accidental lifecycle churn, but they do not by themselves prove side-effect correctness.
- For MV-first guidance and rationale, see
references/mv-patterns.md.
Large-view handling
When a SwiftUI view file exceeds ~300 lines, split it aggressively. Extract meaningful sections into dedicated View types instead of hiding complexity in many computed properties. Use private extensions with // MARK: - comments for actions and helpers, but do not treat extensions as a substitute for breaking a giant screen into smaller view types. If an extracted subview is reused or independently meaningful, move it into its own file.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

