重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
ios-swiftui-patterns by thebushidocollective/han
npx skills add https://github.com/thebushidocollective/han --skill ios-swiftui-patterns适用于 iOS、macOS、watchOS 和 tvOS 应用程序的现代声明式 UI 开发。
SwiftUI 为不同的状态需求提供了一系列属性包装器:
@Observable
class UserModel {
var name: String = ""
var email: String = ""
var isLoggedIn: Bool = false
}
struct ContentView: View {
@State private var user = UserModel()
var body: some View {
UserProfileView(user: user)
}
}
class UserViewModel: ObservableObject {
@Published var name: String = ""
@Published var isLoading: Bool = false
func fetchUser() async {
isLoading = true
defer { isLoading = false }
// 获取逻辑
}
}
struct UserView: View {
@StateObject private var viewModel = UserViewModel()
var body: some View {
// 视图实现
}
}
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
将复杂视图拆分为更小、更专注的组件:
struct OrderSummaryView: View {
let order: Order
var body: some View {
VStack(spacing: 16) {
OrderHeaderView(order: order)
OrderItemsListView(items: order.items)
OrderTotalView(total: order.total)
}
}
}
尽可能使用结构体作为模型,以利用 SwiftUI 高效的差异比较:
struct Product: Identifiable, Equatable {
let id: UUID
var name: String
var price: Decimal
var quantity: Int
}
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())
}
}
struct UserDetailView: View {
let userId: String
@State private var user: User?
var body: some View {
Group {
if let user {
UserContent(user: user)
} else {
ProgressView()
}
}
.task {
user = await fetchUser(id: userId)
}
}
}
struct ContentView: View {
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
ProductListView()
.navigationDestination(for: Product.self) { product in
ProductDetailView(product: product)
}
.navigationDestination(for: Category.self) { category in
CategoryView(category: category)
}
}
}
}
struct ItemView: View {
@State private var showingDetail = false
@State private var showingDeleteAlert = false
var body: some View {
Button("查看详情") {
showingDetail = true
}
.sheet(isPresented: $showingDetail) {
DetailSheet()
}
.alert("删除项目?", isPresented: $showingDeleteAlert) {
Button("删除", role: .destructive) { deleteItem() }
Button("取消", role: .cancel) { }
}
}
}
@Model
class Task {
var title: String
var isCompleted: Bool
var createdAt: Date
init(title: String) {
self.title = title
self.isCompleted = false
self.createdAt = Date()
}
}
struct TaskListView: View {
@Query(sort: \Task.createdAt, order: .reverse)
private var tasks: [Task]
@Environment(\.modelContext) private var modelContext
var body: some View {
List(tasks) { task in
TaskRowView(task: task)
}
}
}
反面示例:
struct BadView: View {
var body: some View {
VStack {
// 超过 200 行的嵌套视图
}
}
}
正面示例:提取为专注的子视图。
反面示例:
struct BadView: View {
@ObservedObject var viewModel = ViewModel() // 每次视图初始化都会重新创建!
}
正面示例:
struct GoodView: View {
@StateObject private var viewModel = ViewModel()
}
反面示例:
var body: some View {
let _ = print("视图已渲染") // 副作用!
Text("你好")
}
正面示例:使用 .task、.onAppear 或 .onChange 来处理副作用。
反面示例:
Text(user!.name) // 有崩溃风险
正面示例:
if let user {
Text(user.name)
}
每周安装量
45
代码仓库
GitHub 星标数
129
首次出现
2026年1月22日
安全审计
安装于
opencode42
codex42
gemini-cli41
github-copilot38
claude-code38
cursor37
Modern declarative UI development for iOS, macOS, watchOS, and tvOS applications.
SwiftUI provides a hierarchy of property wrappers for different state needs:
@Observable
class UserModel {
var name: String = ""
var email: String = ""
var isLoggedIn: Bool = false
}
struct ContentView: View {
@State private var user = UserModel()
var body: some View {
UserProfileView(user: user)
}
}
class UserViewModel: ObservableObject {
@Published var name: String = ""
@Published var isLoading: Bool = false
func fetchUser() async {
isLoading = true
defer { isLoading = false }
// fetch logic
}
}
struct UserView: View {
@StateObject private var viewModel = UserViewModel()
var body: some View {
// view implementation
}
}
Break complex views into smaller, focused components:
struct OrderSummaryView: View {
let order: Order
var body: some View {
VStack(spacing: 16) {
OrderHeaderView(order: order)
OrderItemsListView(items: order.items)
OrderTotalView(total: order.total)
}
}
}
Use structs for models when possible to leverage SwiftUI's efficient diffing:
struct Product: Identifiable, Equatable {
let id: UUID
var name: String
var price: Decimal
var quantity: Int
}
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())
}
}
struct UserDetailView: View {
let userId: String
@State private var user: User?
var body: some View {
Group {
if let user {
UserContent(user: user)
} else {
ProgressView()
}
}
.task {
user = await fetchUser(id: userId)
}
}
}
struct ContentView: View {
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
ProductListView()
.navigationDestination(for: Product.self) { product in
ProductDetailView(product: product)
}
.navigationDestination(for: Category.self) { category in
CategoryView(category: category)
}
}
}
}
struct ItemView: View {
@State private var showingDetail = false
@State private var showingDeleteAlert = false
var body: some View {
Button("View Details") {
showingDetail = true
}
.sheet(isPresented: $showingDetail) {
DetailSheet()
}
.alert("Delete Item?", isPresented: $showingDeleteAlert) {
Button("Delete", role: .destructive) { deleteItem() }
Button("Cancel", role: .cancel) { }
}
}
}
@Model
class Task {
var title: String
var isCompleted: Bool
var createdAt: Date
init(title: String) {
self.title = title
self.isCompleted = false
self.createdAt = Date()
}
}
struct TaskListView: View {
@Query(sort: \Task.createdAt, order: .reverse)
private var tasks: [Task]
@Environment(\.modelContext) private var modelContext
var body: some View {
List(tasks) { task in
TaskRowView(task: task)
}
}
}
Bad:
struct BadView: View {
var body: some View {
VStack {
// 200+ lines of nested views
}
}
}
Good: Extract into focused subviews.
Bad:
struct BadView: View {
@ObservedObject var viewModel = ViewModel() // Re-created on every view init!
}
Good:
struct GoodView: View {
@StateObject private var viewModel = ViewModel()
}
Bad:
var body: some View {
let _ = print("View rendered") // Side effect!
Text("Hello")
}
Good: Use .task, .onAppear, or .onChange for side effects.
Bad:
Text(user!.name) // Crash risk
Good:
if let user {
Text(user.name)
}
Weekly Installs
45
Repository
GitHub Stars
129
First Seen
Jan 22, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode42
codex42
gemini-cli41
github-copilot38
claude-code38
cursor37