关于 swiftui-view-refactor
面向重构 SwiftUI 视图的开发者技能,提供结构、Model-View 模式和 Observation 用法指导。重点是保持视图轻量且可组合,将业务逻辑放在模型或服务中,并保留现有行为。
主要功能
- 01统一视图属性的排列顺序
- 02采用轻量的 Model-View 结构
- 03将复杂 body 拆分为子视图
- 04一致地处理已有视图模型
- 05通过 @State 使用 Observation
适用场景
- 01重构时调整 SwiftUI 视图顺序
- 02将较大的 body 拆分为多个部分
- 03重构已有视图模型的视图
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ steipete/ agent-scripts --skill swiftui-view-refactor安装后在 Claude Code 中输入/swiftui-view-refactor确认已加载。
附带文件references/mv-patterns.md
详细介绍
SwiftUI 视图重构
致谢:摘自 @Dimillian 的 Dimillian/Skills(2025-12-31)。
概述
为 SwiftUI 视图应用一致的结构和依赖模式,重点关注排序、Model-View(MV)模式、谨慎处理视图模型,以及正确使用 Observation。
核心指南
1) 视图排序(从上到下)
- Environment
private/publiclet@State/ 其他存储属性- 计算属性
var(非视图) initbody- 计算视图构建器 / 其他视图辅助方法
- 辅助函数 / 异步函数
2) 优先采用 MV(Model-View)模式
- 默认采用 MV:视图是轻量的状态表达,模型和服务负责业务逻辑。
- 优先使用
@State、@Environment、@Query和task/onChange进行编排。 - 通过
@Environment注入服务和共享模型;让视图保持轻量且易于组合。 - 将大型视图拆分为子视图,而不是引入视图模型。
3) 拆分较大的主体和视图属性
- 如果
body超出一屏或包含多个逻辑区块,请将其拆分成较小的子视图。 - 如果较大的计算视图属性(
var header: some View { ... })包含状态或复杂分支,请将其提取为专用的View类型。 - 可以将相关子视图作为计算视图属性保留在同一文件中;只有在结构上合理或计划复用时,才提取为独立的
View结构体。 - 优先传递少量输入(数据、绑定、回调),而不是复用整个父视图状态。
示例(提取一个区块):
var body: some View {
VStack(alignment: .leading, spacing: 16) {
HeaderSection(title: title, isPinned: isPinned)
DetailsSection(details: details)
ActionsSection(onSave: onSave, onCancel: onCancel)
}
}
示例(较长的主体 → 更短的主体 + 同一文件中的计算视图):
var body: some View {
List {
header
filters
results
footer
}
}
private var header: some View {
VStack(alignment: .leading, spacing: 6) {
Text(title).font(.title2)
Text(subtitle).font(.subheadline)
}
}
private var filters: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(filterOptions, id: \.self) { option in
FilterChip(option: option, isSelected: option == selectedFilter)
.onTapGesture { selectedFilter = option }
}
}
}
}
示例(提取复杂的计算视图):
private var header: some View {
HeaderSection(title: title, subtitle: subtitle, status: status)
}
private struct HeaderSection: View {
let title: String
let subtitle: String?
let status: Status
var body: some View {
VStack(alignment: .leading, spacing: 4) {
Text(title).font(.headline)
if let subtitle { Text(subtitle).font(.subheadline) }
StatusBadge(status: status)
}
}
}
4) 视图模型处理(仅适用于已有视图模型的情况)
- 除非请求或现有代码明确需要,否则不要引入视图模型。
- 如果已有视图模型,请尽可能将其设为非可选。
- 通过
init将依赖传递给视图,然后在视图的init中将这些依赖传递给视图模型。 - 避免使用
bootstrapIfNeeded模式。
示例(基于 Observation):
@State private var viewModel: SomeViewModel
init(dependency: Dependency) {
_viewModel = State(initialValue: SomeViewModel(dependency: dependency))
}
5) Observation 的使用
- 对于
@Observable引用类型,在根视图中将其存储为@State。 - 根据需要显式向下传递可观察对象;除非确有需要,否则避免使用可选状态。
工作流
- 重新排列视图,使其符合排序规则。
- 优先采用 MV:使用
@State、@Environment、@Query、task和onChange,将轻量编排移入视图。 - 如果存在视图模型,请将可选视图模型替换为非可选的
@State视图模型,并在init中传入视图依赖进行初始化。 - 确认 Observation 的使用方式:根视图中的
@Observable视图模型使用@State,不要使用多余的包装器。 - 保持行为不变:除非有明确要求,否则不要更改布局或业务逻辑。
备注
- 优先使用简洁、明确的辅助方法,而不是大型条件代码块。
- 将计算视图构建器放在
body之后,将非视图计算属性放在init之前。 - 关于 MV 优先的指导和原因,请参阅
references/mv-patterns.md。
评论
支持 Markdown