AI Skill Report Card

Auditing SwiftUI View Consistency

A90·Oct 6, 2026·Source: Web
Markdown
--- name: auditing-swiftui-view-consistency description: Performs comprehensive consistency and quality audits of SwiftUI View layers in migrated or legacy iOS codebases, focusing on API consistency, view composition, reusable components, styling, state management, navigation, accessibility, and performance. Use when reviewing a post-migration SwiftUI codebase for inconsistent patterns, UIKit migration artifacts, or when establishing project-wide SwiftUI conventions without changing business logic or architecture. --- # Auditing SwiftUI View Consistency Perform a scoped, evidence-based audit of the View layer only. This is a consistency/quality audit, not a general refactor. Never touch business logic, networking, or app architecture.
14 / 15
Phase 0: Discover conventions (read-only, no edits)
Phase 1: Inventory all Views + categorize by pattern
Phase 2: Cross-module diff of equivalent patterns
Phase 3: Pick "preferred implementation" per pattern (prefer existing, most-used, most idiomatic)
Phase 4: Apply minimal, targeted fixes toward the preferred pattern
Phase 5: Validate (build + existing UI/snapshot tests only — no new test authoring unless asked)
Phase 6: Report (summary, changes, standardized patterns, remaining issues, validation)

Do not write code until Phase 0 and Phase 1 are complete.

Recommendation▾
Add a concrete final report template/skeleton (section headers with placeholder content) rather than just referencing it by name
15 / 15

Progress:

  • Phase 0: Map existing architecture, design system, navigation approach, deployment target
  • Phase 1: Inventory every View file; tag with patterns used (presentation, state, styling, composition)
  • Phase 2: Build a cross-module comparison table for each recurring UI/code pattern
  • Phase 3: Select the preferred implementation per pattern (justify choice)
  • Phase 4: Apply changes, one pattern category at a time, smallest diff that achieves consistency
  • Phase 5: Run build / existing tests / SwiftUI previews sanity check
  • Phase 6: Produce the Final Report (see template below)

Phase 0 — Discover Before Touching Anything

Answer these before any edit:

  • What deployment target / minimum iOS version is set? (Determines which modern APIs — @Observable, NavigationStack, .presentationDetents, etc. — are actually usable.)
  • Is there an existing design-system layer (color/spacing/typography constants, reusable components, custom modifiers)? Where does it live?
  • Is there a navigation/coordinator architecture already established? How do Views currently trigger navigation?
  • What state-management convention dominates — @StateObject/@ObservedObject/ObservableObject, or modern @Observable?
  • Which patterns look migration-generated (literal UIKit translations) vs. hand-written idiomatic SwiftUI?

Never assume — grep for actual usage counts before declaring a pattern "standard."

Phase 1 — Inventory

For every SwiftUI View file, record:

  • Presentation APIs used (.sheet, .fullScreenCover, .popover, .alert, .confirmationDialog)
  • State property wrappers used and whether appropriate
  • Composition shape (body size, nesting depth, extracted subviews vs inline)
  • Styling approach (design-system tokens vs magic numbers)
  • Any UIViewRepresentable/UIViewControllerRepresentable usage and whether still necessary
  • Accessibility modifiers present/absent
  • Lifecycle hooks (.onAppear, .task, .onChange) and what they do

Keep this as a working table — it's the evidence base for Phase 2/3, and source material for the final report.

Phase 2 — Cross-Module Comparison

Group findings by pattern category (see Review Areas list below). For each category, list every distinct implementation found and which module/file it's in. Do not evaluate file-by-file in isolation — the goal is spotting "Module A does X one way, Module B does it differently."

Phase 3 — Choose the Preferred Pattern

For each inconsistency, pick a winner using this priority order:

  1. An existing shared/reusable component or design-system modifier already in the project
  2. The most idiomatic modern SwiftUI approach compatible with the deployment target
  3. The implementation used in the most places (majority convention)
  4. The simplest, most readable option if no clear precedent exists

Document the reason for each choice — this goes directly into "Patterns Standardized."

Phase 4 — Apply Changes

Rules while editing:

  • One pattern category per pass (e.g., fix all .sheet(isPresented:) → .sheet(item:) inconsistencies together, then move to next category).
  • Preserve visual behavior and UX exactly — this is a consistency pass, not a redesign.
  • Reuse existing components/constants; do not invent new design-system values.
  • Do not extract a new reusable View unless the duplicate pattern appears in ≥2 real places (not hypothetically).
  • Do not touch files/areas outside the View layer (no editing ViewModels' business logic, services, networking).
  • Keep diffs minimal and reviewable — avoid drive-by formatting or unrelated cleanup.

Phase 5 — Validate

Only claim what was actually run:

  • Build the project (xcodebuild build or equivalent) — report pass/fail.
  • Run existing unit/UI/snapshot tests — report pass/fail counts.
  • If no tests exist for affected Views, say so explicitly; do not fabricate coverage.
  • Manually sanity-check SwiftUI Previews compile where feasible.
Recommendation▾
Include an example showing a 'bad outcome' — e.g., an audit that over-reached into business logic — to reinforce boundaries

Use this as the taxonomy for Phase 1/2 — not a prescription of what to fix.

API consistency: .sheet vs .fullScreenCover, .sheet(item:) vs boolean-driven, .navigationDestination, NavigationStack/NavigationPath, .toolbar, .safeAreaInset, .overlay vs ZStack, .background, .clipShape, .contentShape, .task, .onAppear/.onDisappear, .onChange, .refreshable, ScrollView/List/LazyVStack, @ViewBuilder, @Binding, @State, @StateObject/@ObservedObject/@EnvironmentObject, @Environment, @Observable.

Composition: oversized Views, deep nesting, duplicated View code, bad extraction boundaries, computed-property-as-view anti-pattern, unnecessary wrapper Views, AnyView/type erasure overuse.

Reusable UI patterns: buttons, headers, nav bars, loading/error/empty states, skeletons, cards, rows, section headers, dialogs, sheets, form fields, pickers, spacing/padding/typography/colors/icons/dividers.

Styling: magic numbers vs design-system tokens for padding, spacing, frame, alignment, fonts, colors, corner radius, shadows, borders, backgrounds, overlays, opacity, animations, transitions.

State/lifecycle: wrong property wrappers, unnecessary/duplicated state, derivable state computed as stored state, wrong @StateObject vs @ObservedObject ownership, unneeded @EnvironmentObject, side effects in body, redundant .onAppear/.task, re-triggering lifecycle calls, cancellation bugs.

Navigation: consistent use of the project's existing coordinator/navigation architecture; no competing navigation mechanisms introduced.

Modern SwiftUI opportunities: @Observable migration (if target supports and project is moving that way), modern toolbar/container/presentation APIs — but only when it improves consistency, not as a trend chase.

UIKit migration artifacts: unnecessary UIViewRepresentable/UIViewControllerRepresentable, imperative UI updates, manual layout SwiftUI can do natively, leftover delegate/coordinator patterns inside Views, duplicated UIKit+SwiftUI implementations.

Accessibility: labels, values, traits, Dynamic Type support, VoiceOver flow, tap target size, semantic grouping, real Button vs raw gesture recognizers.

Performance: expensive work in body, unstable id in ForEach, unnecessary AnyView, over-recomputation, duplicated async work, unnecessarily large hierarchies.

17 / 20

Example 1 — Presentation inconsistency Input: ProfileView uses .sheet(isPresented: $showEditor) { EditorView(user: user) } while SettingsView uses .sheet(item: $selectedSetting) { setting in DetailView(setting) } for conceptually identical "present detail on selection" flows. Output: Standardize on .sheet(item:) wherever the presented content depends on a specific selected value (matches majority usage + avoids stale-state bugs); keep boolean .sheet(isPresented:) only for parameterless flows (e.g., a plain "show info" sheet).

Example 2 — Styling drift Input: Three different card components each hardcode cornerRadius: 12, cornerRadius: 10, and cornerRadius: 14 with ad hoc shadow values, while DesignSystem.CornerRadius.card exists and is used in two other modules. Output: Replace all three hardcoded values with DesignSystem.CornerRadius.card; do not invent a new shared constant since one already exists.

Example 3 — UIKit artifact Input: A UIViewRepresentable wraps UIActivityIndicatorView for a loading spinner even though the project already uses ProgressView elsewhere. Output: Replace with native ProgressView, matching the dominant pattern; remove the now-unused representable wrapper.

Recommendation▾
Add a brief example of the Phase 2 cross-module comparison table format to make that step more concrete
  • Lead with grep/search across the whole project before judging any single file — consistency issues are invisible without cross-module comparison.
  • Prefer the pattern that's already dominant or already backed by a design-system component — don't impose personal taste.
  • Keep every change traceable to a specific, named inconsistency; no silent drive-by edits.
  • Respect the deployment target — don't suggest @Observable or iOS 17+ APIs if the project targets iOS 15.
  • When multiple valid implementations exist and no clear winner, pick the simplest and flag it in the report rather than agonizing.
  • Treat the coordinator/navigation architecture as fixed; only make Views call into it consistently.
  • Starting to edit Views before completing the discovery/inventory phase.
  • Extracting new reusable components for patterns that only appear once.
  • Replacing a working API with a "more modern" one purely because it's newer, ignoring deployment target or project convention.
  • Fixing styling by introducing new magic numbers instead of reusing existing design-system tokens.
  • Letting the audit creep into ViewModel/business-logic/network-layer changes.
  • Claiming tests or builds were run without actually executing them.
  • Silently changing UX/visual behavior while "standardizing" an API.
  • Removing UIKit interop that is still genuinely required (e.g., no SwiftUI equivalent exists yet).
0
Grade AAI Skill Framework
Scorecard
Criteria Breakdown
Quick Start
14/15
Workflow
15/15
Examples
17/20
Completeness
16/20
Format
15/15
Conciseness
13/15