OA0 = Omni AI 0
OA0 是一个探索 AI 的论坛
现在注册
已注册用户请  登录
OA0  ›  技能包  ›  swiftui-view-refactor:SwiftUI 视图文件重构与审查

swiftui-view-refactor:SwiftUI 视图文件重构与审查

 
  paas ·  2026-02-04 21:14:26 · 3 次点击  · 0 条评论  

名称: swiftui-view-refactor
描述: 重构和审查 SwiftUI 视图文件,以确保结构一致、依赖注入正确以及合理使用 Observation。适用于需要清理 SwiftUI 视图布局/顺序、安全处理视图模型(尽可能使用非可选类型)或标准化依赖项与 @Observable 状态的初始化和传递方式的场景。


SwiftUI 视图重构

来源:复制自 @Dimillian 的 Dimillian/Skills (2025-12-31)。

概述

为 SwiftUI 视图应用一致的结构和依赖模式,重点关注顺序、模型-视图 (MV) 模式、谨慎的视图模型处理以及正确的 Observation 使用。

核心准则

1) 视图顺序(从上到下)

  • Environment
  • private/public let
  • @State / 其他存储属性
  • 计算属性 var(非视图)
  • init
  • body
  • 计算视图构建器 / 其他视图辅助工具
  • 辅助函数 / 异步函数

2) 优先使用 MV(模型-视图)模式

  • 默认采用 MV 模式:视图是轻量级的状态表达;模型/服务拥有业务逻辑。
  • 优先使用 @State@Environment@Query 以及 task/onChange 进行状态协调。
  • 通过 @Environment 注入服务和共享模型;保持视图小巧且可组合。
  • 将大型视图拆分为子视图,而不是引入视图模型。

3) 拆分大型 body 和视图属性

  • 如果 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)
    }
}

示例(长 body → 短 body + 同一文件内的计算视图):

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 存储在根视图中。
  • 根据需要显式向下传递可观察对象;除非必要,避免使用可选状态。

工作流程

1) 重新排序视图以符合顺序规则。
2) 优先采用 MV 模式:使用 @State@Environment@QuerytaskonChange 将轻量级协调逻辑移至视图中。
3) 如果视图模型存在,用非可选的 @State 视图模型替换可选视图模型,并在 init 中通过视图传递的依赖项进行初始化。
4) 确认 Observation 使用:根 @Observable 视图模型使用 @State,避免冗余包装器。
5) 保持行为不变:除非请求,否则不更改布局或业务逻辑。

注意事项

  • 优先使用小巧、明确的辅助函数,而非大型条件代码块。
  • 将计算视图构建器放在 body 下方,非视图计算属性放在 init 上方。
  • 有关 MV 优先的指导和原理,请参阅 references/mv-patterns.md
3 次点击  ∙  0 人收藏  
登录后收藏  
0 条回复
About   ·   Help   ·    
OA0 - Omni AI 0 一个探索 AI 的社区
沪ICP备2024103595号-2
Developed with Cursor