用途
本技能面向使用 Tuist 和 SwiftUI 开发 macOS 菜单栏应用(menubar app)的场景,可用于新建、重构或审阅这类应用。目标是建立以 Tuist 为先的工作流和稳定的启动脚本,并保持严格的架构边界,使网络、状态与 UI 保持可测试、可预测。
核心规则
- 除非被明确要求,否则应用保持为仅菜单栏形态,默认使用 LSUIElement = true。
- 传输与解码逻辑保持在视图之外,不要在 SwiftUI 视图体内调用网络请求。
- 状态变更放在 store 层(@Observable 或等价方案),不要写在行/视图呈现代码中。
- 模型解码要对 API 漂移保持容错:使用可选字段、安全回退和防御式解析。
- 将 Tuist 清单视为唯一真实来源,不要依赖手工编辑的生成版 Xcode 产物。
- 当 tuist run 在 macOS 目标/设备解析上不可靠时,本地迭代优先使用基于脚本的启动方式。
- 构建生成项目时,在本地运行脚本中优先使用 tuist xcodebuild build,而不是直接用原生 xcodebuild。
推荐的文件结构
默认采用以下放置方式:
- Project.swift:应用 target、设置、资源、Info.plist 键
- Sources/Model.swift:API/领域模型与解码
- Sources/Client.swift:请求、响应映射、传输相关关注点
- Sources/Store.swift:可观察状态、刷新策略、过滤、缓存
- Sources/MenuView*.swift:菜单组合与顶层 UI 状态
- Sources/RowView*.swift:行渲染与轻量交互
- run-menubar.sh:本地重启/构建/启动的标准路径
- stop-menubar.sh:需要时用于显式停止的辅助脚本
工作流程
- 确认 Tuist 所有权:核实 Tuist.swift 与 Project.swift(或 workspace 清单)是否存在;在改动启动行为前先阅读已有的运行脚本。
- 在编码假设前先探测后端行为:使用 curl 验证接口形态、鉴权要求和分页行为;如果端点忽略 limit/page,则在 store 中实现全量列表处理并在本地裁剪。
- 自底向上实现各层:先定义/调整模型;再新增或更新 client 请求/解码逻辑;然后更新 store 的刷新、过滤与缓存策略;最后接线视图。
- 保持应用接线最小化:应用入口专注于 scene/menu 接线与依赖注入,避免在 App 或菜单 scene 声明中嵌入业务逻辑。
- 统一启动体验:确保运行脚本在重新启动前先重启已有实例;确保运行脚本不会附带打开 Xcode;需要生成时使用 tuist generate --no-open;当运行脚本构建生成项目时,优先使用 TUIST_SKIP_UPDATE_CHECK=1 tuist xcodebuild build ... 而不是直接调用原生 xcodebuild。
验证矩阵
编辑后运行以下验证:
- TUIST_SKIP_UPDATE_CHECK=1 tuist xcodebuild build -scheme <TargetName> -configuration Debug
如果启动流程有改动:
- ./run-menubar.sh
如果 shell 脚本有改动:
- bash -n run-menubar.sh
- bash -n stop-menubar.sh
- ./run-menubar.sh
失败模式与修复方向
- tuist run 无法解析 macOS destination:改用 run/stop 脚本作为标准本地运行路径。
- 刷新后菜单 UI 卡顿或不一致:将派生状态与过滤移入 store,让视图保持只渲染。
- API 载荷变化导致解码失败:通过可选字段和默认值放宽模型解码,再在 UI 中安全呈现缺失数据。
- 功能要求快速打 UI 补丁:在改动行/菜单呈现之前,先在 model/client/store 中追根因。
完成检查清单
- 除非被明确更改,否则保持仅菜单栏行为。
- 将网络与状态逻辑排除在 SwiftUI 视图体之外。
- 保持 Tuist 清单与运行脚本和实际构建/运行流程一致。
- 对触及区域运行验证矩阵。
- 报告实际执行的命令及其结果。