swiftui-patterns-developer
SwiftUI view structure, composition, and best practices. Use when refactoring SwiftUI views, organizing view files, or extracting subviews.
Install
mkdir -p .claude/skills/swiftui-patterns-developer && curl -L -o skill.zip "https://mcp.directory/api/skills/download/6716" && unzip -o skill.zip -d .claude/skills/swiftui-patterns-developer && rm skill.zipInstalls to .claude/skills/swiftui-patterns-developer
About this skill
SwiftUI Patterns Developer (Smart Router)
Purpose
Apply consistent structure and patterns to SwiftUI views, with focus on ordering, subview extraction, and proper composition.
When Auto-Activated
- Refactoring SwiftUI view structure
- Organizing view file layout
- Splitting large views into subviews
- Keywords: view structure, view ordering, split view, extract subview, large view, refactor view
Core Guidelines
0) Three Qualities of SwiftUI Views (WWDC24)
Understanding these fundamentals helps you write better SwiftUI code:
1. Declarative - Describe what you want, not how to create it:
// ✅ Declarative - describe the result
List(pets) { pet in
HStack {
Text(pet.name)
Spacer()
Text(pet.species)
}
}
// No need to add/remove rows manually - SwiftUI handles it
2. Compositional - Build complex UIs from simple building blocks:
// ViewBuilder closures define children of containers
HStack { // Container view
Image(...) // Child 1
VStack { // Child 2 (also a container)
Text(...) // Nested child
Text(...) // Nested child
}
Spacer() // Child 3
}
3. State-Driven - UI automatically updates when state changes:
// SwiftUI tracks dependencies and updates views automatically
@State private var count = 0
var body: some View {
Button("Count: \(count)") { // Dependency on `count`
count += 1 // State change triggers re-render
}
}
Key insight: Views are VALUE TYPES (structs), not long-lived objects. They are descriptions of current UI state, not objects that receive commands over time. SwiftUI maintains the actual UI behind the scenes.
1) View Ordering (top -> bottom)
Follow Anytype's property organization from IOS_DEVELOPMENT_GUIDE.md:
struct ExampleView: View {
// 1. Property wrappers (@State, @Injected, @Environment)
@State private var model: ExampleViewModel
@Injected(\.settingsService) private var settingsService
@Environment(\.dismiss) private var dismiss
// 2. Public properties (let/var)
let title: String
// 3. Private properties
private var cancellables = Set<AnyCancellable>()
// 4. Computed properties
private var hasItems: Bool { !model.items.isEmpty }
// 5. init (if needed)
init(title: String) {
self.title = title
_model = State(wrappedValue: ExampleViewModel(title: title))
}
// 6. body
var body: some View {
content
.task { await model.startSubscriptions() }
}
// 7. Computed view builders
private var content: some View { ... }
// 8. Helper / async functions
private func handleTap() { ... }
}
2) ViewModel Pattern (Anytype Standard)
Anytype uses MVVM with ViewModels. Always use ViewModels for business logic:
// View - lightweight, UI only
struct ChatView: View {
@State private var model: ChatViewModel
init(spaceId: String, chatId: String) {
_model = State(wrappedValue: ChatViewModel(spaceId: spaceId, chatId: chatId))
}
var body: some View {
content
.task { await model.startSubscriptions() }
}
private var content: some View {
List(model.messages) { message in
MessageRow(message: message)
}
}
}
// ViewModel - handles business logic
@MainActor
@Observable
final class ChatViewModel {
var messages: [Message] = []
@ObservationIgnored
@Injected(\.chatService) private var chatService
func startSubscriptions() async {
// Heavy work here, not in init
}
func sendMessage(_ text: String) async {
// Business logic
}
}
Key points:
- Use
@State private var model: ViewModelin views - Initialize ViewModel in view's
initwith_model = State(wrappedValue:) - Keep ViewModel init cheap, heavy work in
.task - Use
@Observablemacro (notObservableObject) - Mark ViewModels with
@MainActor
3) How Observation Works (WWDC23)
Understanding why @Observable works helps you use it correctly.
Property Access Tracking:
- SwiftUI tracks which properties you access during
bodyevaluation - Only those accessed properties trigger view invalidation when changed
- Properties NOT read in
bodydon't cause re-renders (unlike@Published)
@Observable
final class SettingsViewModel {
var userName: String = "" // Accessed in body → triggers update
var isLoading: Bool = false // Accessed in body → triggers update
var analyticsData: Data = Data() // NOT accessed in body → no update
}
struct SettingsView: View {
@State private var model: SettingsViewModel
var body: some View {
// SwiftUI tracks: "this view reads userName and isLoading"
VStack {
Text(model.userName) // ✓ Tracked
if model.isLoading { // ✓ Tracked
ProgressView()
}
// model.analyticsData not read → changes won't invalidate this view
}
}
}
Per-Instance Tracking:
- Arrays of
@Observableobjects work efficiently - Only the specific instance that changed triggers updates
- No need for
identifiabletricks with observation
@Observable
final class MessageViewModel {
var text: String
var isRead: Bool = false
}
// Each MessageRow only updates when ITS message changes
List(model.messages) { message in
MessageRow(message: message) // Only this row updates when message.isRead changes
}
Computed Properties Just Work:
- Computed properties composed from stored properties are automatically tracked
- SwiftUI traces through to the underlying stored properties
@Observable
final class CartViewModel {
var items: [Item] = []
var discount: Double = 0
// Computed → tracks both `items` and `discount`
var totalPrice: Double {
items.reduce(0) { $0 + $1.price } - discount
}
}
Performance Benefit:
With @Observable, views only update when properties they actually read change. This is more efficient than ObservableObject where ANY @Published change triggers objectWillChange for ALL subscribers.
4) Property Wrapper Decision Tree
When to use which wrapper with @Observable:
| Scenario | Wrapper | Why |
|---|---|---|
| View owns model lifecycle | @State | View creates and manages the model |
| Model shared app-wide | @Environment | Injected at app root, read anywhere |
| Just need bindings ($syntax) | @Bindable | Pass to TextField, Toggle, etc. |
| Just reading the model | Nothing | Direct property access triggers tracking |
// View OWNS the model (creates it)
struct ChatView: View {
@State private var model: ChatViewModel // ← @State
init(chatId: String) {
_model = State(wrappedValue: ChatViewModel(chatId: chatId))
}
}
// Model passed from parent, need bindings
struct MessageEditor: View {
@Bindable var draft: DraftMessage // ← @Bindable for $draft.text
var body: some View {
TextField("Message", text: $draft.text)
}
}
// Just reading, no bindings needed
struct MessageRow: View {
let message: MessageViewModel // ← Nothing! Just read properties
var body: some View {
Text(message.text)
Image(systemName: message.isRead ? "checkmark.circle.fill" : "circle")
}
}
Migration from ObservableObject:
| Old | New |
|---|---|
@StateObject | @State |
@ObservedObject | @Bindable or nothing |
@EnvironmentObject | @Environment |
5) Migration from ObservableObject (WWDC23)
Step-by-step conversion from legacy ObservableObject:
Before (ObservableObject):
class SettingsViewModel: ObservableObject {
@Published var userName: String = ""
@Published var notifications: Bool = true
private var cancellables = Set<AnyCancellable>()
}
struct SettingsView: View {
@StateObject private var model = SettingsViewModel()
var body: some View {
TextField("Name", text: $model.userName)
Toggle("Notifications", isOn: $model.notifications)
}
}
After (@Observable):
@Observable
final class SettingsViewModel {
var userName: String = ""
var notifications: Bool = true
@ObservationIgnored
private var cancellables = Set<AnyCancellable>()
}
struct SettingsView: View {
@State private var model = SettingsViewModel()
var body: some View {
@Bindable var model = model // Local binding for $ syntax
TextField("Name", text: $model.userName)
Toggle("Notifications", isOn: $model.notifications)
}
}
Migration Steps:
- Remove
ObservableObjectconformance, add@Observablemacro - Remove
@Publishedfrom all properties (observation is automatic) - Add
@ObservationIgnoredto properties that shouldn't trigger updates - Change
@StateObject→@Statein views - For
$binding syntax, use@Bindable var model = modelin body - Replace
@EnvironmentObjectwith@Environment
Note: Anytype already uses @Observable - this section is for understanding legacy code during migrations.
6) Dependency Injection (Factory)
Anytype uses Factory DI, not SwiftUI Environment for services:
// ✅ CORRECT - Factory DI
@Injected(\.chatService) private var chatService
// ❌ WRONG - Environment for services
@Environment(ChatService.self) private var chatService
Environment is for:
- System values:
@Environment(\.dismiss),@Environment(\.colorScheme) - SwiftUI-provided context
@Injected is for:
- App services:
@Injected(\.chatService) - Repositories:
@Injected(\.userRepository) - Any business logic dependencies
7) View Modifiers and Order (WWDC24)
View modifiers create a hierarchical structure. Order matters - modifiers are applied sequentially:
// Eac
---
*Content truncated.*
More by anyproto
View all skills by anyproto →You might also like
flutter-development
aj-geddes
Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.
drawio-diagrams-enhanced
jgtolentino
Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.
ui-ux-pro-max
nextlevelbuilder
"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."
godot
bfollington
This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.
nano-banana-pro
garg-aayush
Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.
fastapi-templates
wshobson
Create production-ready FastAPI projects with async patterns, dependency injection, and comprehensive error handling. Use when building new FastAPI applications or setting up backend API projects.
Related MCP Servers
Browse all serversSupercharge AI platforms with Azure MCP Server for seamless Azure API Management and resource automation. Public Preview
Unlock seamless Salesforce org management with the secure, flexible Salesforce DX MCP Server. Streamline workflows and b
Manage Alibaba Cloud ECS, monitor metrics, and configure VPC networks effortlessly using natural language commands with
Get structured & freeform code reviews with code quality analysis tools powered by OpenAI, Google & Anthropic. Supports
Learn how to create a server in Minecraft efficiently. Use npx tool to scaffold an MCP server with templates and best pr
Discover the best ever TV series with our TV Show Recommender. Get personalized picks, trends, and streaming info from T
Stay ahead of the MCP ecosystem
Get weekly updates on new skills and servers.