SwiftUIExpertSkill swiftui-expert-skill

这项技能专注于使用SwiftUI构建、审查和改进特性,遵循最佳实践,包括状态管理、现代API使用、Swift并发、视图组合和性能优化。

移动开发 0 次安装 0 次浏览 更新于 3/2/2026

SwiftUI专家技能

概览

使用这项技能构建、审查或改进SwiftUI特性,确保正确的状态管理、现代API使用、Swift并发最佳实践、最优视图组合以及iOS 26+液态玻璃风格。优先考虑原生API、苹果设计指南和性能意识模式。这项技能专注于事实和最佳实践,而不是强制执行特定的架构模式。

工作流程决策树

1) 审查现有的SwiftUI代码

  • 根据选择指南检查属性包装器使用情况(见references/state-management.md
  • 验证现代API使用情况(见references/modern-apis.md
  • 验证视图组合是否遵循提取规则(见references/view-structure.md
  • 检查是否应用了性能模式(见references/performance-patterns.md
  • 验证列表模式使用稳定身份(见references/list-patterns.md
  • 检查液态玻璃使用的准确性和一致性(见references/liquid-glass.md
  • 验证iOS 26+可用性处理和合理的回退

2) 改进现有的SwiftUI代码

  • 审计状态管理以正确选择包装器(优先选择@Observable而不是ObservableObject
  • 用现代等价物替换过时的API(见references/modern-apis.md
  • 将复杂视图提取到单独的子视图中(见references/view-structure.md
  • 重构热路径以最小化冗余状态更新(见references/performance-patterns.md
  • 确保ForEach使用稳定身份(见references/list-patterns.md
  • 建议在UIImage(data:)使用时进行图像降采样(作为可选优化,见references/image-optimization.md
  • 仅在用户明确请求时采用液态玻璃

3) 实施新的SwiftUI特性

  • 首先设计数据流:确定拥有与注入状态(见references/state-management.md
  • 使用现代API(不使用过时的修饰符或模式,见references/modern-apis.md
  • 对于共享状态使用@Observable(如果不使用默认actor隔离,则使用@MainActor
  • 为最优diffing结构化视图(早期提取子视图,保持视图小,见references/view-structure.md
  • 将业务逻辑分离到可测试的模型中(见references/layout-best-practices.md
  • 在布局/外观修饰符后应用玻璃效果(见references/liquid-glass.md
  • 使用#available限制iOS 26+特性,并提供回退

核心指南

状态管理

  • 对于新代码,始终优先选择@Observable而不是ObservableObject
  • 除非使用默认actor隔离,否则用@MainActor标记@Observable
  • 始终将@State@StateObject标记为private(使依赖关系清晰)
  • 永远不要将传递值声明为@State@StateObject(它们只接受初始值)
  • @Observable类一起使用@State(而不是@StateObject
  • 仅当子视图需要修改父状态时使用@Binding
  • 需要绑定的注入@Observable对象使用@Bindable
  • 将只读值用于let;将var + .onChange()用于响应式读取
  • 遗留:@StateObject用于拥有的ObservableObject@ObservedObject用于注入的
  • 嵌套ObservableObject不起作用(直接将嵌套对象传递给子视图);@Observable很好地处理嵌套

现代API

  • 使用foregroundStyle()而不是foregroundColor()
  • 使用clipShape(.rect(cornerRadius:))而不是cornerRadius()
  • 使用Tab API而不是tabItem()
  • 使用Button而不是onTapGesture()(除非需要位置/计数)
  • 使用NavigationStack而不是NavigationView
  • 使用navigationDestination(for:)进行类型安全导航
  • 使用双参数或无参数onChange()变体
  • 使用ImageRenderer渲染SwiftUI视图
  • 使用.sheet(item:)而不是.sheet(isPresented:)进行基于模型的内容
  • 表单应拥有自己的操作并内部调用dismiss()
  • 使用ScrollViewReader进行稳定ID的程序滚动
  • 避免使用UIScreen.main.bounds进行尺寸调整
  • 避免GeometryReader,当存在替代方案时(例如,containerRelativeFrame()

Swift最佳实践

  • 使用现代文本格式化(.format参数,而不是String(format:)
  • 使用localizedStandardContains()进行用户输入过滤(而不是contains()
  • 优先使用静态成员查找(.blueColor.blue
  • 使用.task修饰符自动取消异步工作
  • 使用.task(id:)进行值依赖任务

视图组合

  • 对于状态变化,优先选择修饰符而不是条件视图(保持视图身份)
  • 将复杂视图提取到单独的子视图中,以提高可读性和性能
  • 保持视图小以获得最佳性能
  • 保持视图body简单纯净(无副作用或复杂逻辑)
  • 仅对小型、简单的部分使用@ViewBuilder函数
  • 优先选择@ViewBuilder let content: Content而不是基于闭包的内容属性
  • 将业务逻辑分离到可测试的模型中(不是关于强制执行架构)
  • 动作处理程序应引用方法,而不是包含内联逻辑
  • 使用相对布局而不是硬编码常数
  • 视图应在任何上下文中工作(不假设屏幕尺寸或呈现样式)

性能

  • 仅将所需值传递给视图(避免大型“配置”或“上下文”对象)
  • 消除不必要的依赖以减少更新扇出
  • 在热路径中分配状态之前检查值变化
  • 避免在onReceiveonChange、滚动处理程序中进行冗余状态更新
  • 在频繁执行的代码路径中最小化工作
  • 对于大型列表使用LazyVStack/LazyHStack
  • 确保ForEach使用稳定身份(从不使用.indices进行动态内容)
  • 确保ForEach元素的视图数量恒定
  • 避免在ForEach中进行内联过滤(预过滤和缓存)
  • 避免在列表行中使用AnyView
  • 考虑使用POD视图进行快速diffing(或将昂贵的视图包装在POD父视图中)
  • 建议在遇到UIImage(data:)时进行图像降采样(作为可选优化)
  • 避免布局抖动(深层层次结构、过度GeometryReader
  • 通过阈值限制频繁的几何更新
  • 使用Self._printChanges()调试意外视图更新

液态玻璃(iOS 26+)

仅在用户明确请求时采用。

  • 使用原生glassEffectGlassEffectContainer和玻璃按钮样式
  • GlassEffectContainer中包装多个玻璃元素
  • 在布局和视觉修饰符后应用.glassEffect()
  • 仅对可点击/可聚焦的元素使用.interactive()
  • 使用glassEffectID@Namespace进行变形过渡

快速参考

属性包装器选择(现代)

包装器 使用时
@State 内部视图状态(必须是private),或拥有的@Observable
@Binding 子视图修改父状态
@Bindable 需要绑定的注入@Observable对象
let 来自父视图的只读值
var 通过.onChange()观察的只读值

遗留(iOS 17之前):

包装器 使用时
@StateObject 视图拥有一个ObservableObject(使用@State@Observable代替)
@ObservedObject 视图接收一个ObservableObject

现代API替代品

过时的 现代替代品
foregroundColor() foregroundStyle()
cornerRadius() clipShape(.rect(cornerRadius:))
tabItem() Tab API
onTapGesture() Button(除非需要位置/计数)
NavigationView NavigationStack
onChange(of:) { value in } onChange(of:) { old, new in }onChange(of:) { }
fontWeight(.bold) bold()
GeometryReader containerRelativeFrame()visualEffect()
showsIndicators: false .scrollIndicators(.hidden)
String(format: "%.2f", value) Text(value, format: .number.precision(.fractionLength(2)))
string.contains(search) string.localizedStandardContains(search)(用于用户输入)

液态玻璃模式

// 基本玻璃效果及回退
if #available(iOS 26, *) {
    content
        .padding()
        .glassEffect(.regular.interactive(), in: .rect(cornerRadius: 16))
} else {
    content
        .padding()
        .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 16))
}

// 分组玻璃元素
GlassEffectContainer(spacing: 24) {
    HStack(spacing: 24) {
        GlassButton1()
        GlassButton2()
    }
}

// 玻璃按钮
Button("Confirm") { }
    .buttonStyle(.glassProminent)

审查清单

状态管理

  • [ ] 对于新代码使用@Observable而不是ObservableObject
  • [ ] 用@MainActor标记@Observable类(如果需要)
  • [ ] 与@Observable类一起使用@State(而不是@StateObject
  • [ ] @State@StateObject属性是private
  • [ ] 传递值未声明为@State@StateObject
  • [ ] 仅在子视图修改父状态时使用@Binding
  • [ ] 需要绑定的注入@Observable使用@Bindable
  • [ ] 避免嵌套ObservableObject(或直接传递给子视图)

现代API(见references/modern-apis.md

  • [ ] 使用foregroundStyle()而不是foregroundColor()
  • [ ] 使用clipShape(.rect(cornerRadius:))而不是cornerRadius()
  • [ ] 使用Tab API而不是tabItem()
  • [ ] 使用Button而不是onTapGesture()(除非需要位置/计数)
  • [ ] 使用NavigationStack而不是NavigationView
  • [ ] 避免使用UIScreen.main.bounds
  • [ ] 尽可能使用GeometryReader的替代品
  • [ ] 按钮图像包括文稿标签以提高可访问性

表单和导航(见references/sheet-navigation-patterns.md

  • [ ] 使用.sheet(item:)进行基于模型的表单
  • [ ] 表单拥有自己的操作并内部取消
  • [ ] 使用navigationDestination(for:)进行类型安全导航

ScrollView(见references/scroll-patterns.md

  • [ ] 使用稳定ID的ScrollViewReader进行程序滚动
  • [ ] 使用.scrollIndicators(.hidden)而不是初始化参数

文本和格式化(见references/text-formatting.md

  • [ ] 使用现代文本格式化(不是String(format:)
  • [ ] 使用localizedStandardContains()进行搜索过滤

视图结构(见references/view-structure.md

  • [ ] 对于状态变化,使用修饰符而不是条件
  • [ ] 将复杂视图提取到单独的子视图中
  • [ ] 保持视图小以获得最佳性能
  • [ ] 容器视图使用@ViewBuilder let content: Content

性能(见references/performance-patterns.md

  • [ ] 视图body保持简单纯净(无副作用)
  • [ ] 仅传递所需值(不是大型配置对象)
  • [ ] 消除不必要的依赖
  • [ ] 在分配状态之前检查值变化
  • [ ] 热路径最小化状态更新
  • [ ] 在body中不创建对象
  • [ ] 将繁重的计算移出body

列表模式(见references/list-patterns.md

  • [ ] ForEach使用稳定身份(不是.indices
  • [ ] ForEach元素的视图数量恒定
  • [ ] ForEach中不进行内联过滤
  • [ ] 列表行中不使用AnyView

布局(见references/layout-best-practices.md

  • [ ] 避免布局抖动(深层层次结构,过度GeometryReader
  • [ ] 通过阈值限制频繁的几何更新
  • [ ] 将业务逻辑分离到可测试的模型中
  • [ ] 动作处理程序引用方法(不是内联逻辑)
  • [ ] 使用相对布局(不是硬编码常数)
  • [ ] 视图在任何上下文中工作(上下文不可知)

液态玻璃(iOS 26+)

  • [ ] 使用#available(iOS 26, *)及液态玻璃的回退
  • [ ] 多个玻璃视图包装在GlassEffectContainer
  • [ ] 在布局/外观修饰符后应用.glassEffect()
  • [ ] .interactive()仅用于用户交互元素
  • [ ] 相关元素的形状和色调保持一致

参考资料

  • references/state-management.md - 属性包装器和数据流(优先选择@Observable
  • references/view-structure.md - 视图组合、提取和容器模式
  • references/performance-patterns.md - 性能优化技术和反模式
  • references/list-patterns.md - ForEach身份、稳定性和列表最佳实践
  • references/layout-best-practices.md - 布局模式、上下文不可知视图和可测试性
  • references/modern-apis.md - 现代API使用和过时替代品
  • references/sheet-navigation-patterns.md - 表单呈现和导航模式
  • references/scroll-patterns.md - ScrollView模式和程序滚动
  • references/text-formatting.md - 现代文本格式化和字符串操作
  • references/image-optimization.md - AsyncImage、图像降采样和优化
  • references/liquid-glass.md - iOS 26+液态玻璃API

哲学

这项技能专注于事实和最佳实践,而不是架构观点:

  • 我们不强制执行特定的架构(例如,MVVM、VIPER)
  • 我们鼓励将业务逻辑分离以进行可测试性
  • 我们优先考虑现代API而不是过时的API
  • 我们强调使用@MainActor@Observable进行线程安全
  • 我们针对性能和可维护性进行优化
  • 我们遵循苹果的人类界面指南和API设计模式