Expert SwiftUI development guidelines with MVVM architecture and modern Swift best practices
This skill covers best practices for building clear, performant, and maintainable SwiftUI applications, including architecture, state management, Swift 6 concurrency, layout, animation, and testing.
@Observable, NavigationStack, #Preview); note the minimum deployment target when it forces older patternsinitbody property — past that, extract subviews into small, reusable structs or private extension functions@ViewBuilder for custom container views and complex conditional view logic@State — local, value-type view state (Bool, Int, String, small structs)@Binding — two-way data binding with child views@StateObject — use only in the view that creates/owns the object's lifecycle@ObservedObject — use in child views that react to changes but don't own the object@EnvironmentObject / @Environment — use sparingly for broadly shared dependencies or system values; prefer explicit dependency injection via init when a dependency belongs to a specific view hierarchy rather than the whole app@Published — for observable properties on ObservableObject classes (pre-iOS 17 or when ObservableObject is otherwise required)@Observable macro (iOS 17+) — prefer this over ObservableObject/@Published for new view models; it removes the need for @Published on every property and only triggers view updates for properties actually read by that view, which reduces unnecessary redrawsfetchUserData over getDatais, has, should, etc.NavigationStack (iOS 16+) over the deprecated NavigationView.background(.blue)).contentShape(Rectangle()) to HStack/VStack rows that have transparent backgrounds, so taps register across the whole row rather than only on opaque contentLazyVStack/LazyHStack for dynamic or long listsGeometryReader sparingly — it expands to fill all available space and can hurt layout performance; prefer .background(GeometryReader { ... }) scoped to a single view, or the Layout protocol for custom layoutsids (from Identifiable) rather than \.selfViewModifiers for reusable styling; create custom ButtonStyle, TextFieldStyle, etc..animation(_:value:) scoped to a specific state value over broad withAnimation calls, especially inside bodywithAnimation for animations explicitly triggered by user interactionAnyTransition; use matchedGeometryEffect for hero animationsTimelineView for high-frequency, time-driven visual updates instead of a Timer + published property@MainActor; all UI updates must happen on the main actor.task(id:) over .onAppear for starting async work — it automatically cancels the task when the view disappears or the id changes, avoiding orphaned workasync/await for asynchronous operations and Result (or typed throws) for error handlingactor types for shared mutable state or services accessed from multiple tasksnonisolated when they don't touch the main actor, to avoid unnecessary hopsTask[weak self] in closures that outlive the current scope; use guard let self else { return } at the start of async closures[unowned self] when the closure's lifetime is provably shorter than self'sguard for early returnsAsyncImage (with a caching layer, or a library like Nuke/Kingfisher for production apps) and apply .resizable() immediatelyEquatable conformance where it helps SwiftUI skip redundant diffingIdentifiable items and stable idsbodyaccessibilityIdentifier strings to interactive elements so UI tests can target them reliably#Preview (Xcode 15+) or PreviewProvider on older toolchains, injecting realistic mock dataMARK: - Section Name to organize longer files, and place private helpers in a private extension@Observable
@MainActor
final class ContentViewModel {
var items: [Item] = []
var isLoading = false
func loadItems() async {
isLoading = true
defer { isLoading = false }
// Load items
}
}
struct ContentView: View {
@State private var viewModel = ContentViewModel()
var body: some View {
List(viewModel.items) { item in
Text(item.name)
}
.task(id: viewModel.items.count) {
await viewModel.loadItems()
}
}
}
struct ContentView: View {
@StateObject private var viewModel = ContentViewModel()
var body: some View {
// View implementation
}
}
@MainActor
class ContentViewModel: ObservableObject {
@Published var items: [Item] = []
@Published var isLoading = false
func loadItems() async {
isLoading = true
// Load items
isLoading = false
}
}
struct CardModifier: ViewModifier {
func body(content: Content) -> some View {
content
.padding()
.background(Color(.systemBackground))
.cornerRadius(12)
.shadow(radius: 4)
}
}
extension View {
func cardStyle() -> some View {
modifier(CardModifier())
}
}
</content>npx skills add Mindrally/swiftui-development下载完整 Skill 目录,包含 SKILL.md 及所有相关文件
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer