blake@xcode:~/Projects$ cat ios-agent-development.md

使用AI智能体构建iOS应用:从业者指南

# 使用AI智能体构建iOS应用

words: 3975 read_time: 34m updated: 2026-04-14 23:53
$ less ios-agent-development.md

概要:三个智能体运行时现已支持 iOS 代码开发:Claude Code CLI(配合 MCP)、Codex CLI(配合 MCP)以及 Xcode 26.3 原生 Intelligence 智能体。两个 MCP 服务器——XcodeBuildMCP(59 个工具)和 Apple 的 xcrun mcpbridge(20 个工具)——为智能体提供了结构化的构建、测试、模拟器和调试访问能力。本指南涵盖真实的 CLAUDE.md 配置模式、Hook 配置方案,以及对哪些有效、哪些会出问题的坦诚评估——源自 8 个生产级 iOS 应用、共计 293 个 Swift 文件的实战经验。智能体擅长处理 SwiftUI 视图、SwiftData 模型、代码重构和构建错误诊断,但在 .pbxproj 修改、代码签名和可视化调试方面力不从心。”智能体能写 Swift”与”智能体能交付 iOS 应用”之间的鸿沟,靠的是配置来弥合,而非提示词。

我用 AI 编码智能体构建了 8 款 iOS 应用。不是原型——而是上架 App Store 的产品,集成了 HealthKit、Metal 着色器、SpriteKit 物理引擎、iCloud 同步、Live Activities、Game Center 排行榜,目标平台横跨 iOS、watchOS 和 tvOS。这些应用中的每一行 Swift 代码,要么由智能体编写、我来审查,要么由我编写、智能体来重构。据我估算,比例大约是 85/15,智能体占大头。

本指南是我入门时希望存在的参考手册。它覆盖了完整的技术栈:选择哪个智能体运行时、如何配置 MCP 服务器以获得结构化构建访问、CLAUDE.md 中该写什么、哪些 Hook 能防止智能体破坏你的 Xcode 项目,以及——最关键的——智能体在哪些环节会失败、需要你亲自接手。

核心要点

iOS 开发者初次接触 AI 智能体:

  • 从 Claude Code CLI + XcodeBuildMCP 开始。这是最成熟的运行时,拥有最深度的 MCP 工具覆盖。安装两条命令,在项目中添加一个 CLAUDE.md,智能体就能自主完成构建、测试和调试,无需你手动复制粘贴错误信息。
  • 绝对不要让智能体修改 .pbxproj。这是最重要的一条规则。一个阻止写入 .pbxproj.xcodeproj/ 的 PreToolUse Hook 能帮你省下数小时的恢复时间。
  • CLAUDE.md 是智能体的入职文档。在 CLAUDE.md 上投入的每一小时,都能省下十小时纠正智能体错误的时间。

有经验的智能体用户将 iOS 纳入工作流:

  • MCP 彻底改变了 iOS 构建循环。在 MCP 出现之前,智能体能写 Swift 但无法验证是否编译通过。有了 XcodeBuildMCP,智能体可以编写代码、执行构建、读取结构化错误、修复问题、运行测试——全程自主完成。
  • 三个运行时各有所长。Claude Code CLI 适合深度智能体会话,Codex CLI 适合无头批量任务,Xcode 26.3 原生智能体适合在 IDE 内快速完成行内修改。
  • Hook 基础设施可以直接复用。现有的 PostToolUse 格式化器、PreToolUse 拦截器和测试运行 Hook 在 iOS 项目中同样适用,只需微调路径即可。

团队负责人评估 AI 辅助 iOS 开发:

  • 智能体效能取决于项目文档质量,而非项目规模。一个有详细 CLAUDE.md 的 63 文件应用,比一个没有文档的 14 文件应用能产出更好的智能体输出。
  • .pbxproj 边界不可逾越。智能体无法可靠地编辑 Xcode 项目文件。工作流中必须考虑手动将文件添加到 Xcode target。
  • 坦诚的 ROI:智能体能处理 70-80% 的实现工作。剩余的 20-30%——视觉打磨、签名、性能调优、App Store 提交——仍需人工判断。

选择你的路径

需求 入口
首次配置 MCP MCP 配置:完整指南——安装两个服务器、验证、配置智能体
为 iOS 项目编写 CLAUDE.md iOS 项目的 CLAUDE.md 模式——来自 8 款应用的真实示例
对比三个智能体运行时 iOS 的三个智能体运行时——Claude Code vs. Codex vs. Xcode 原生
了解智能体的能力边界 智能体的优势领域智能体的薄弱环节
配置 iOS 开发 Hook iOS 开发 Hook——保存时格式化、.pbxproj 保护、测试运行器
完整参考(本页) 继续阅读——从配置到高级模式,应有尽有

如何使用本指南

本指南超过 3,000 行,建议根据你的经验水平选择起点:

经验水平 从这里开始 然后探索
iOS 和智能体都是新手 前置条件MCP 配置你的第一次智能体会话 CLAUDE.md 模式哪些有效/无效
iOS 开发者,初次使用智能体 三个运行时MCP 配置CLAUDE.md Hook架构模式
智能体用户,初次接触 iOS 架构模式智能体的薄弱环节CLAUDE.md 框架专项上下文高级工作流
两者都有经验 高级工作流Hook多平台模式 运行时对比矩阵作品集:8 款应用,293 个文件

目录

  1. 作品集:8 款应用,293 个文件
  2. 前置条件
  3. iOS 的三个智能体运行时
  4. MCP 配置:完整指南
  5. iOS 项目的 CLAUDE.md 模式
  6. 你的第一次智能体会话
  7. 智能体在 iOS 中的优势领域
  8. 智能体在 iOS 中的薄弱环节
  9. iOS 开发 Hook
  10. 适配智能体的架构模式
  11. 框架专项上下文
  12. 多平台模式
  13. 高级工作流
  14. 真实案例分析
  15. 智能体参与的项目全生命周期
  16. 智能体定义配置
  17. 智能体辅助 iOS 的测试模式
  18. iOS 项目的上下文窗口管理
  19. 故障排除
  20. 智能体在 iOS 中的常见错误及预防
  21. 坦诚评估
  22. 常见问题
  23. 快速参考卡片
  24. 参考资料

相关资源

主题 资源
为 Xcode 配置 MCP(简短博文) 两个 MCP 服务器让 Claude Code 成为 iOS 构建系统
Claude Code CLI 完整参考 Claude Code CLI:完整指南
Codex CLI 参考 Codex CLI:完整指南
Hook 系统深度解析 解剖一只爪:84 个 Hook 作为编排层
智能体架构模式 智能体架构指南

项目组合:8款应用,293个文件

在深入配置之前,先了解本指南的实践基础。这些并非玩具项目——它们横跨五个Apple框架、三个平台,涵盖iOS开发的全部复杂度,从14个文件的健身追踪器到63个文件的多平台冥想计时器,一应俱全。

应用 技术栈 文件数 复杂度
Banana List SwiftUI + SwiftData + iCloud Drive同步 + MCP服务器用于Claude Desktop 53 完整CRUD、iCloud同步、自定义MCP服务器将应用数据暴露给Claude Desktop
Ace Citizenship SwiftUI学习应用 + FastAPI后端 26 客户端-服务器架构、REST API集成、测验引擎
TappyColor SpriteKit颜色匹配游戏 30 游戏循环、物理引擎、触摸处理、粒子效果
Return 禅意冥想计时器——iOS 26+、watchOS、tvOS 63 HealthKit、Live Activities、Watch扩展运行时、TV焦点导航、iCloud会话同步
amp97 Metal着色器 + 音频可视化 41 自定义Metal渲染管线、音频分析、实时GPU计算
Reps SwiftUI + SwiftData健身追踪 14 最小可行应用,简洁的SwiftData模式
Water SwiftUI + SwiftData + Metal + HealthKit饮水追踪 34 Metal流体模拟、HealthKit饮水量记录、小组件
Starfield Destroyer SpriteKit + Metal太空射击游戏 32 99个关卡、8艘飞船、Game Center排行榜、Metal后处理

为什么文件数量很重要:Agent的效果取决于项目的可读性,而非项目规模。Return(63个文件)比amp97(41个文件)能产出更好的Agent输出,因为Return拥有详尽的CLAUDE.md,包含文件注释、架构图和明确的设计模式。而amp97的Metal着色器本身就更难被Agent理解,无论文档质量如何。


前置条件

在为iOS开发配置任何Agent运行时之前:

必需: - macOS 15+(Sequoia)或macOS Tahoe - Xcode 26.3+已安装并配置完成(已接受许可协议、已下载平台组件) - 至少安装一个iOS Simulator运行时 - 一个Anthropic API账户(用于Claude Code)或OpenAI账户(用于Codex)

推荐: - 安装SwiftFormatbrew install swiftformat)——用于保存时自动格式化的hooks - 安装SwiftLintbrew install swiftlint)——可选,但有助于代码风格统一 - 熟悉终端操作——三种运行时均通过命令行运行或与命令行集成

验证Xcode安装:

# Check Xcode version
xcodebuild -version
# Expected: Xcode 26.3 or later

# Check available simulators
xcrun simctl list devices available
# Expected: at least one iPhone simulator

# Verify xcrun mcpbridge is available
xcrun mcpbridge --help
# Expected: usage information (not "command not found")

如果xcrun mcpbridge返回”command not found”,说明需要Xcode 26.3或更高版本。请通过App Store或developer.apple.com安装或更新Xcode。注意:xcode-select --install仅安装命令行工具,不包含mcpbridge——必须安装完整的Xcode.app。


iOS的三种Agent运行时

三种不同的运行时可以编写、构建和测试iOS代码。它们并非可以互换——每种运行时有不同的优势、不同的MCP集成模式和不同的理想使用场景。

1. Claude Code CLI

简介:Anthropic基于终端的智能编程助手。能够读取代码库、执行命令、修改文件,并通过MCP连接外部工具。

MCP集成:完整支持XcodeBuildMCP和Apple的Xcode MCP。Agent通过MCP协议发现工具,并以结构化参数调用。两个服务器共提供59 + 20个工具。

配置:

# Install Claude Code (if not already installed)
claude --version  # verify installation

# Add XcodeBuildMCP (59 tools — builds, tests, simulators, debugging)
claude mcp add XcodeBuildMCP \
  -s user \
  -e XCODEBUILDMCP_SENTRY_DISABLED=true \
  -- npx -y xcodebuildmcp@latest mcp

# Add Apple Xcode MCP (20 tools — file ops, diagnostics, Swift REPL, previews)
claude mcp add --transport stdio xcode \
  -s user -- xcrun mcpbridge

最佳场景:深度实现会话——构建新功能、跨文件重构、调试复杂问题、自主运行构建-测试-修复循环。Claude Code的1M上下文窗口(搭配Opus 4.6)意味着Agent可以将大多数中小型iOS项目完整载入工作记忆——根据实际经验,大约可处理50个文件,具体取决于文件大小。

典型会话:

You: Add a new SettingsView with toggles for notifications and haptic feedback.
     Use the existing Settings.swift pattern from TimerManager.
     Build for simulator after implementation and fix any errors.

Claude: [reads Settings.swift, TimerManager.swift, existing views]
        [creates SettingsView.swift]
        [calls build_sim via MCP]
        [reads structured error: missing import HealthKit]
        [fixes import]
        [calls build_sim again  success, 0 errors, 1 warning]
        [calls test_sim  all tests pass]

与MCP出现之前的工作流相比,关键区别在于:Agent不再需要让你手动构建或粘贴错误输出。构建-报错-修复循环完全自主完成。

2. Codex CLI

简介:OpenAI的终端编程Agent。概念上与Claude Code类似,但使用OpenAI模型(GPT-4o、o3),且权限模型有所不同。

MCP集成:Codex通过codex mcp add命令支持MCP。Apple的Xcode MCP可直接使用:

# Add Apple Xcode MCP to Codex
codex mcp add xcode -- xcrun mcpbridge

XcodeBuildMCP同样适用于Codex,使用相同的npx命令:

# Add XcodeBuildMCP to Codex
codex mcp add XcodeBuildMCP -- npx -y xcodebuildmcp@latest mcp

最佳场景:无界面批处理操作、CI/CD集成,以及需要从不同模型系列获取第二意见的场景。Codex的沙盒模式在隔离环境中运行代码,适合运行会修改状态的测试套件等破坏性操作。

与Claude Code的主要区别: - 使用OpenAI模型而非Claude模型 - 上下文窗口大小和token计费方式不同 - 沙盒优先的权限模型(默认更严格) - MCP生态较小(经过验证的社区服务器更少) - Hooks系统可用(v0.119.0+),但不如Claude Code成熟——事件类型更少,且缺少条件判断的if字段

何时在iOS开发中选择Codex而非Claude Code:

当你需要模型多样性时使用Codex——让第二个Agent审查第一个Agent编写的代码,能捕获不同类别的错误。协作工作流(Claude构建,Codex审查)对iOS开发尤为有效,因为一个模型系列认为正确的SwiftUI模式可能存在另一个模型能发现的细微问题。Metal着色器和并发模式尤其受益于双模型审查。

3. Xcode 26.3原生Agent

简介:Apple将AI编程Agent直接集成到了Xcode的Intelligence面板中。从Xcode 26.3起,可以在Xcode设置 > Intelligence中配置Claude Agent和Codex作为智能服务提供方。

配置:

  1. 打开Xcode 26.3+
  2. 进入Settings > Intelligence
  3. 添加新的提供方:
  4. Claude:选择”Claude Agent”,输入Anthropic API密钥
  5. Codex:选择”Codex”,输入OpenAI API密钥
  6. Agent出现在Intelligence侧边栏中,可内联调用

最佳场景:快速内联编辑、具备Agent级推理能力的代码补全,以及不愿离开Xcode的开发者。原生集成意味着Agent可以直接访问Xcode的项目上下文——打开的文件、构建目标、scheme配置——无需MCP桥接。

与CLI Agent相比的局限: - 没有hook系统——无法实现保存时自动格式化或阻止.pbxproj写入 - 不加载CLAUDE.md——Agent不读取项目级配置文件 - 自主性有限——Agent只能操作当前文件或选区,无法跨整个项目工作 - 不支持子Agent委派——复杂的多步骤任务无法并行处理 - 不支持MCP服务器配置——Agent仅使用Xcode内置工具

何时使用Xcode原生Agent:

适合快速、范围明确的编辑,切换到终端反而是额外负担的场景。比如”给这个模型添加一个计算属性”、”为这个函数编写单元测试”、”将这个视图重构为使用@Observable”。这类任务只涉及一两个文件,不需要构建-测试循环。

对于需要构建、测试、多文件重构或自主错误修正的任务,请使用搭配MCP的CLI Agent。

运行时对比矩阵

能力 Claude Code CLI Codex CLI Xcode 26.3原生
MCP支持 完整(79个工具) 完整(79个工具) 仅Xcode内置工具
Hook系统 有(成熟) 有(基础,v0.119.0+)
CLAUDE.md / 项目配置 codex.md等效方案
自主构建-测试-修复 有(通过MCP) 有(通过MCP) 部分(仅内联)
子Agent委派 有(最多10个并行)
上下文窗口 1M tokens(Opus 4.6) 因模型而异 因提供方而异
多文件操作 完整代码库访问 完整代码库访问 当前文件/选区
.pbxproj保护 通过hooks 手动 不适用(原生使用Xcode)
保存时格式化 通过PostToolUse hooks 外部工具 Xcode设置
离线能力
计费模式 Anthropic API用量 OpenAI API用量 提供方API用量

建议:以Claude Code CLI作为主力运行时。Xcode 26.3原生Agent用于快速内联编辑。Codex CLI用于代码审查和批处理操作。三者互补而非竞争。


MCP 配置:完整设置指南

MCP(Model Context Protocol)能将 AI 代理从”写完 Swift 代码然后祈祷你去构建”转变为”写完 Swift 代码、自行构建、读取结构化错误并修复”。本节内容比博客文章更加深入——涵盖两个服务器、所有安装方式、验证流程,以及确保工具被实际调用的代理配置。

XcodeBuildMCP:59 个无界面 iOS 开发工具

XcodeBuildMCPxcodebuildxcrun simctl 和 LLDB 封装为 59 个结构化的 MCP 工具。无需启动 Xcode 即可运行——整个构建-测试-调试周期通过 Apple 命令行工具以无界面方式完成。

安装方式:

# Option 1: Via npx (recommended — always uses latest version)
claude mcp add XcodeBuildMCP \
  -s user \
  -e XCODEBUILDMCP_SENTRY_DISABLED=true \
  -- npx -y xcodebuildmcp@latest mcp

# Option 2: Via Homebrew (pinned version, manual updates)
brew install xcodebuildmcp
claude mcp add XcodeBuildMCP \
  -s user \
  -e XCODEBUILDMCP_SENTRY_DISABLED=true \
  -- xcodebuildmcp mcp

# Option 3: Project-scoped (omit -s user)
claude mcp add XcodeBuildMCP \
  -e XCODEBUILDMCP_SENTRY_DISABLED=true \
  -- npx -y xcodebuildmcp@latest mcp

-s user 标志使服务器在所有项目中全局可用。省略此标志则为项目级安装(适用于仅在 iOS 项目中启用 MCP,而非 Web 项目的场景)。

-e XCODEBUILDMCP_SENTRY_DISABLED=true 环境变量用于禁用崩溃报告遥测。XcodeBuildMCP 默认包含 Sentry,会发送包括文件路径在内的错误数据。除非您希望为项目贡献诊断数据,否则建议选择退出。1

完整工具清单(59 个工具,分为 8 个类别):

类别 工具 功能说明
项目发现 discover_projslist_schemeslist_targets 查找 .xcodeproj/.xcworkspace 文件,列出可用的 scheme 和 target
构建 build_simbuild_devicebuild_mac 构建并输出按文件和行号分类的结构化 JSON 错误/警告信息
测试 test_simtest_device 运行测试并返回按方法分类的通过/失败结果
模拟器生命周期 list_simsboot_simshutdown_simopen_simsession_set_defaults 创建、启动、管理和配置模拟器
设备管理 list_devicesinstall_devicelaunch_device 真机部署与管理
调试 debug_attach_simdebug_attach_devicedebug_breakpointdebug_stackdebug_variablesdebug_evaldebug_continuedebug_stepdebug_detach 完整的 LLDB 集成,支持断点和变量检查
UI 自动化 snapshot_uiscreenshottapswipetype_text 自动化交互与可视化截图
项目脚手架 create_projectadd_fileadd_package 创建项目并添加依赖

日常开发中最重要的工具:

  1. build_sim — 这是使用频率最高的工具。它返回按文件、行号和严重程度分类的 JSON 错误信息。代理读取错误后会自动导航到对应文件进行修复,全程无需人工介入。

  2. test_sim — 返回按测试方法分类的结果。代理能精确定位哪个测试失败及失败原因,而非仅仅显示”测试失败”。

  3. list_sims + boot_sim — 无需记忆 xcrun simctl 的各种参数即可管理模拟器。代理会自动发现可用的运行时环境并选择合适的设备。

  4. discover_projs + list_schemes — 项目自省能力。代理无需猜测 scheme 名称或工作区结构。

  5. debug_attach_sim + debug_stack + debug_variables — 远程 LLDB 调试。代理可以设置断点、检查变量、逐步执行代码,无需打开调试器。

Apple Xcode MCP:20 个连接 Xcode 的桥接工具

Apple 的 MCP 服务器随 Xcode 26.3 一同发布,通过 xcrun mcpbridge 运行。它通过 XPC(Apple 的进程间通信框架)与正在运行的 Xcode 进程通信,暴露出任何 CLI 工具都无法访问的内部状态。

安装方式:

# Standard installation (global)
claude mcp add --transport stdio xcode \
  -s user -- xcrun mcpbridge

# For Codex CLI
codex mcp add xcode -- xcrun mcpbridge

需要 Xcode 26.3 及以上版本,且 Xcode 进程必须处于运行状态。 如果 Xcode 未打开,通过此服务器发起的所有 MCP 调用都会失败或挂起。XcodeBuildMCP 则没有这一限制。

工具清单(20 个工具,分为 5 个类别):

类别 工具 功能说明
文件操作 XcodeReadXcodeWriteXcodeUpdateXcodeGlobXcodeGrep 在 Xcode 项目上下文中读写文件
构建与测试 BuildProjectGetBuildLogRunAllTestsRunSomeTests 使用 Xcode 内部构建系统进行构建和测试
诊断 XcodeListNavigatorIssuesXcodeRefreshCodeIssuesInFile 实时代码诊断(不仅限于构建错误)
代码与文档 ExecuteSnippetDocumentationSearch Swift REPL 执行和 Apple 文档搜索
预览 RenderPreview 无界面 SwiftUI 预览渲染

Apple MCP 独有的工具(XcodeBuildMCP 中不可用):

  1. DocumentationSearch — 搜索 Apple 开发者文档,包括 WWDC 专题演讲。对于 Apple API 相关问题,比网页搜索更快速、更可靠。例如询问”HKQuantityType(.dietaryWater) 是否有效?”即可从源头获得权威答案。

  2. ExecuteSnippet — 在项目上下文中执行 Swift REPL。代理可以验证 API 行为、测试类型转换并校验表达式,无需构建完整应用。

  3. RenderPreview — 以无界面方式渲染 SwiftUI 预览。代理可以检查视图是否正常渲染,但无法评估视觉效果的正确性(渲染结果以数据形式返回,而非可视化检查)。

  4. XcodeListNavigatorIssues — 返回 Xcode 分析器的实时诊断信息,不仅限于构建错误。能捕获未使用变量、潜在循环引用、弃用警告等构建系统不会显示的问题。

为何需要两个服务器

两者在构建和测试方面有所重叠,但本质上存在根本差异:

┌─────────────────────────────────────────────────────────────────┐
                     MCP TOOL COVERAGE                           
├─────────────────────────────────────────────────────────────────┤
                                                                 
  XcodeBuildMCP (59 tools)        Apple Xcode MCP (20 tools)    
  ┌─────────────────────┐         ┌─────────────────────┐       
   Standalone                     Requires Xcode             
   (no Xcode process)            (XPC bridge)               
                                                            
    Simulators          BOTH     Documentation            
    Real devices       ┌─────┐   Swift REPL               
    LLDB debugging     Build   SwiftUI previews         
    UI automation      Test    Live diagnostics         
    Project scaffold   └─────┘   Analyzer issues          
    Screenshot                                             
  └─────────────────────┘         └─────────────────────┘       
                                                                 
└─────────────────────────────────────────────────────────────────┘

XcodeBuildMCP 适用于: 构建-测试-调试循环。无需打开 Xcode 即可运行,占用更少系统内存,提供更丰富的模拟器和设备管理功能。这是您的主要构建工具。

Apple Xcode MCP 适用于: 文档查询、Swift REPL 验证、SwiftUI 预览渲染和实时诊断。在需要这些功能的开发会话中保持 Xcode 处于打开状态即可。

实际使用中: 我大约 90% 的 MCP 调用使用 XcodeBuildMCP,Apple Xcode MCP 主要用于文档查询和 REPL 验证。代理默认使用 XcodeBuildMCP 进行构建和测试,因为它更快(无 Xcode 进程开销)且更可靠(无 XPC 依赖)。

验证

安装两个服务器后,验证它们是否已正确连接:

# List all configured MCP servers
claude mcp list

# Expected output includes:
# XcodeBuildMCP: npx -y xcodebuildmcp@latest mcp - Connected
# xcode: xcrun mcpbridge - Connected

如果服务器显示”Disconnected”或未出现:

  1. XcodeBuildMCP 无法连接: 确保已安装 Node.js(node --version)。npx 命令需要 Node.js 18 及以上版本。
  2. Apple Xcode MCP 无法连接: 确保已安装 Xcode 26.3 及以上版本,且 xcrun mcpbridge 命令在终端中可正常执行。至少打开 Xcode 一次以接受许可协议。
  3. 两者均未显示: 重启 Claude Code(在新终端中运行 claude)。会话中途注册的 MCP 服务器可能需要重启后才会生效。

教会代理使用 MCP

安装 MCP 服务器是必要条件,但并非充分条件。如果没有明确的引导,代理可能会退回到通过 Bash 运行 xcodebuild(非结构化输出,浪费上下文 token),或者使用网页搜索查阅 Apple 文档(速度更慢、可靠性更低)。

将以下内容添加到您的 CLAUDE.md 或代理定义中:

## 构建与测试 - 始终使用 MCP

所有构建操作应优先使用 MCP 工具,而非原始 shell 命令:

- **构建**`build_sim` / `build_device`(而非通过 Bash 执行 `xcodebuild`- **测试**`test_sim` / `test_device`(而非通过 Bash 执行 `xcodebuild test`- **模拟器**`list_sims``boot_sim``open_sim`(而非通过 Bash 执行 `xcrun simctl`- **调试**`debug_attach_sim``debug_stack``debug_variables`
- **Apple 文档**`DocumentationSearch`(而非使用 WebSearch 搜索 Apple API)
- **Swift 验证**`ExecuteSnippet`(而非通过 Bash 执行 `swift`- **预览**`RenderPreview` 用于无界面 SwiftUI 验证

MCP 返回结构化 JSON。Bash 返回非结构化文本。
结构化数据意味着更少的 token 消耗和更精准的错误诊断。

这一指导确保智能体会优先使用 MCP 工具。否则,智能体往往会通过 Bash 构造冗长的 xcodebuild 命令,在解析输出时消耗数千个上下文 token,有时还会误判实际错误。


适用于 iOS 项目的 CLAUDE.md 模式

CLAUDE.md 是项目中对智能体辅助开发最重要的文件。它是智能体的入职文档——决定了新成员是熟读了架构文档还是在盲目猜测。

我维护的每个 iOS 项目都有一份 CLAUDE.md。以下是从全部 8 个应用中总结出的有效模式。

必备章节

每个 iOS 项目的 CLAUDE.md 都需要以下六个章节,其余均为可选。

1. 项目身份

# Return - Zen Focus Timer

**Bundle ID:** `com.941apps.Return`
**Target:** iOS 26+ / macOS Tahoe / watchOS 26+ / tvOS 26+
**Architecture:** SwiftUI with @Observable pattern, companion Watch and TV apps
**Swift version:** 6.2
**Minimum deployment:** iOS 26.0

为什么这很重要:智能体在编写任何代码之前都需要了解部署目标。面向 iOS 17 的智能体会使用 NavigationView@ObservedObject,而面向 iOS 26 的智能体会使用 NavigationStack@Observable。Bundle ID 对权限配置和 HealthKit 设置至关重要。Swift 版本决定了并发模型(async/await 还是完成回调,严格并发还是宽松并发)。

2. 带用途标注的文件结构

## File Structure

Return/ ├── ReturnApp.swift # App entry, dark mode enforcement ├── ContentView.swift # Main timer view with theme backgrounds ├── TimerManager.swift # Timer state, logic, and repeat handling ├── AudioManager.swift # Sound playback with AVAudioPlayer ├── Settings.swift # Centralized settings with validation ├── SettingsSheet.swift # Settings UI ├── HealthKitManager.swift # Mindful session logging + cross-device sync ├── LiveActivityManager.swift # Lock Screen/Dynamic Island ├── Theme.swift # Theme definitions ├── ThemeManager.swift # Theme state management ├── VideoBackgroundView.swift # AVPlayer video backgrounds ├── GlassTextShape.swift # Core Text glyph paths for glass effect ├── GlassTimerText.swift # Timer text with glass material └── Constants.swift # App constants


每个文件名后的行内注释并非装饰,而是你能写出的最高效文档。当智能体需要决定在哪里添加新功能时,这些标注能引导它一次命中正确文件,而非逐一读取每个文件来了解项目布局。

反模式: 列出文件却不加标注。TimerManager.swift 无法告诉智能体它处理的是状态、UI 还是两者兼有。而 TimerManager.swift # Timer state, logic, and repeat handling 则清楚说明了哪些内容应该放在这里,哪些不应该。

3. 构建和测试命令

## Build & Test

Build for iOS simulator:
```bash
xcodebuild -scheme Return -destination 'platform=iOS Simulator,name=iPhone 16 Pro' build

Run tests:

xcodebuild -scheme Return -destination 'platform=iOS Simulator,name=iPhone 16 Pro' test

Run tvOS tests:

xcodebuild -scheme ReturnTV -destination 'platform=tvOS Simulator,name=Apple TV' test

Prefer MCP tools (build_sim, test_sim) over these raw commands. MCP returns structured JSON with categorized errors.

即使智能体应优先使用 MCP,仍需包含原始命令。这些命令作为备用文档,同时明确了 scheme 名称和目标设备。

#### 4. 关键模式与规则

```markdown

## Key Patterns

### Observable Architecture
- ALL view models use `@Observable` (NEVER `ObservableObject`)
- ALL navigation uses `NavigationStack` (NEVER `NavigationView`)
- State management via `@Observable` classes with `@MainActor` isolation

### Settings Pattern
- Centralized `Settings.shared` singleton
- All settings bounded to valid ranges with validation
- Sound names validated against whitelist
- Thread-safe access via @MainActor

### Audio System
- `AVAudioPlayer` with `.playback` category (plays in silent mode)
- Silent audio loop for background execution
- Bell playback with completion callbacks and token-based staleness

这些模式防止智能体引入不一致性。如果没有明确的模式文档,智能体有时会在一个文件中使用 ObservableObject,在另一个文件中使用 @Observable,或者创建新的设置机制而非使用现有的 Settings.shared 单例。

5. 智能体绝对不能做的事

## Rules

- **NEVER modify .pbxproj files** — create Swift files, then I will add them to Xcode manually
- **NEVER modify .xcodeproj/ contents directly**
- **NEVER add new package dependencies** without asking first
- **NEVER change the deployment target**
- **NEVER modify entitlements files** unless explicitly asked
- **NEVER use NavigationView** — always NavigationStack
- **NEVER use ObservableObject** — always @Observable
- **NEVER use @StateObject** — always @State with @Observable

明确的禁止规则比隐含的期望更有效。智能体遵守否定约束的可靠性远高于肯定建议,因为前者是二元判断(做或不做),而非启发式判断(优先选择这个/有时使用那个)。

6. 框架特定上下文

此章节因应用而异。对于任何有非显而易见配置的框架,都应包含此内容:

针对 HealthKit 应用:

## HealthKit Configuration

- Entitlement: `com.apple.developer.healthkit`
- Info.plist keys:
  - `NSHealthShareUsageDescription`: "Return reads your mindful minutes..."
  - `NSHealthUpdateUsageDescription`: "Return logs meditation sessions..."
- Category types: `HKCategoryType(.mindfulSession)`
- Authorization checked on every write (user can revoke at any time)
- HealthKit is unavailable on tvOS — guard with `#if canImport(HealthKit)`

针对 SwiftData 应用:

## SwiftData Models

### Model Relationships
- `GroceryList` has many `GroceryItem` (cascade delete)
- `GroceryItem` belongs to one `GroceryList`
- `GroceryItem` has optional `Category`

### Model Container Setup
- Configured in App struct with `modelContainer(for:)`
- Schema versioning: currently V2
- Migration plan: `GroceryMigrationPlan` handles V1 → V2

### Queries
- `@Query(sort: \GroceryItem.name)` for sorted fetches
- `@Query(filter: #Predicate { !$0.isCompleted })` for active items
- Always use `@Query` in views, `modelContext.fetch()` in managers

针对 SpriteKit 应用:

## SpriteKit Scene Hierarchy

GameScene (SKScene) ├── backgroundLayer (SKNode, zPosition: -100) │ └── StarfieldNode (custom, parallax scrolling) ├── gameLayer (SKNode, zPosition: 0) │ ├── playerShip (PlayerNode, zPosition: 10) │ ├── enemyContainer (SKNode, zPosition: 5) │ └── bulletPool (SKNode, zPosition: 8) ├── effectsLayer (SKNode, zPosition: 50) │ └── ParticleManager (manages explosion/trail emitters) └── hudLayer (SKNode, zPosition: 100) ├── scoreLabel (SKLabelNode) └── healthBar (HealthBarNode)

- Physics categories defined in `PhysicsCategory.swift` as bitmasks
- Contact detection via `didBegin(_ contact:)` on GameScene
- Bullet pooling: pre-allocate 50, recycle via `removeFromParent()` + re-add

针对 Metal 应用:

## Metal Pipeline

- Render pipeline: `MetalView``Renderer``ShaderLibrary`
- Compute pipeline: `AudioAnalyzer` → compute shader → texture output
- Shared uniforms struct: `Uniforms` in `ShaderTypes.h` (bridged to Swift)
- Frame timing: `CADisplayLink` drives render loop
- Buffer triple-buffering: 3 in-flight frames with semaphore

### Shader Files
- `Shaders.metal` — Main render shaders (vertex + fragment)
- `Compute.metal` — Audio analysis compute kernel
- `PostProcess.metal` — Bloom and color grading

### DO NOT modify Metal shaders without testing on device.
Simulator Metal is not representative of device GPU behavior.

实际 CLAUDE.md 示例:Banana List(SwiftUI + SwiftData + iCloud + MCP Server)

以下是一个带注释的示例,展示了六个章节如何在中等复杂度的应用中协同工作。这是我为 Banana List 使用的 CLAUDE.md 模式——一个包含 53 个文件的杂货清单应用,支持 iCloud 同步,并配有自定义 MCP 服务器将应用数据暴露给 Claude Desktop:

# Banana List - Grocery List App

**Bundle ID:** `com.941apps.BananaList`
**Target:** iOS 26+
**Architecture:** SwiftUI + SwiftData + iCloud Drive sync
**Swift version:** 6.2
**Minimum deployment:** iOS 26.0

## Core Features

- Grocery lists with items, categories, and quantities
- iCloud Drive sync via SwiftData CloudKit integration
- Custom MCP server exposing list data to Claude Desktop
- Liquid Glass design system
- Haptic feedback on interactions
- Share sheets for list sharing

## 文件结构

BananaList/ ├── BananaListApp.swift # App entry, model container setup ├── Models/ │ ├── GroceryList.swift # @Model: list with name, items, color │ ├── GroceryItem.swift # @Model: item with name, quantity, category, isCompleted │ ├── Category.swift # @Model: user-defined categories │ └── SampleData.swift # Preview and test data ├── Views/ │ ├── ListsView.swift # Main list of grocery lists │ ├── ListDetailView.swift # Items within a list │ ├── ItemRow.swift # Single item row with swipe actions │ ├── AddItemSheet.swift # New item form │ ├── CategoryPicker.swift # Category selection with create-new │ └── SettingsView.swift # App settings ├── Managers/ │ ├── CloudSyncManager.swift # iCloud Drive sync status and conflict resolution │ └── HapticManager.swift # UIImpactFeedbackGenerator wrapper ├── MCP/ │ ├── MCPServer.swift # MCP server for Claude Desktop integration │ ├── ListTools.swift # MCP tools: list CRUD operations │ └── ItemTools.swift # MCP tools: item CRUD operations └── Extensions/ ├── Color+Extensions.swift # Custom color definitions └── View+Extensions.swift # Reusable view modifiers

## SwiftData 模型

### 关系映射
- `GroceryList` 拥有多个 `GroceryItem`(级联删除)
- `GroceryItem` 属于一个 `GroceryList`(必填)
- `GroceryItem` 可选关联 `Category`
- `Category` 拥有多个 `GroceryItem`(删除时置空)

### 容器配置
```swift
@main
struct BananaListApp: App {
    var body: some Scene {
        WindowGroup {
            ListsView()
        }
        .modelContainer(for: [GroceryList.self, GroceryItem.self, Category.self])
    }
}

查询模式

  • 列表查询:@Query(sort: \GroceryList.name) var lists: [GroceryList]
  • 未完成项:@Query(filter: #Predicate { !$0.isCompleted })
  • 按分类筛选:获取后在内存中过滤(受 SwiftData 谓词限制)

构建与测试

xcodebuild -scheme BananaList -destination 'platform=iOS Simulator,name=iPhone 16 Pro' build
xcodebuild -scheme BananaList -destination 'platform=iOS Simulator,name=iPhone 16 Pro' test

建议优先使用 MCP 工具(build_simtest_sim),而非直接执行原始命令。

关键模式

Observable + SwiftData

  • SwiftData 的 @Model 类自动具备 Observable 能力
  • 切勿@Model 类上添加 @Observable(冗余操作,会触发警告)
  • 在表单中使用 @Bindable 实现模型属性的双向绑定
  • 视图中使用 @Query,非视图代码中使用 modelContext.fetch()

iCloud 同步

  • 通过 SwiftData CloudKit 集成自动完成同步
  • 冲突解决策略:以最后写入为准(CloudKit 默认行为)
  • 同步状态通过 CloudSyncManager.shared.syncState 暴露
  • 测试同步时需在两台模拟器上使用同一 iCloud 账号

MCP 服务器架构

  • 作为本地 WebSocket 服务器运行,监听端口 8765
  • 暴露 6 个工具:listAll、getList、createList、addItem、completeItem、deleteItem
  • Claude Desktop 通过 ~/.config/claude-desktop/config.json 中的 MCP 配置进行连接

规则

  • 绝对禁止修改 .pbxproj 或 .xcodeproj 内容
  • 绝对禁止在未更新 SampleData.swift 的情况下变更模型 schema
  • 绝对禁止使用 ObservableObject —— SwiftData 模型已自带 Observable 能力
  • 绝对禁止使用 @StateObject —— 应配合 @Observable 类使用 @State
  • 绝对禁止使用 NavigationView —— 始终使用 NavigationStack
  • 绝对禁止@Model 类上添加 @Observable
  • 务必使用 @Bindable 实现表单中模型属性的绑定
  • 务必在两台模拟器实例上测试 iCloud 同步变更
### 真实 CLAUDE.md 示例:Reps(极简 SwiftData 应用——14个文件)

对于小型项目,CLAUDE.md 可以十分精简。以下是 Reps 的配置模式,这是一个仅有 14 个文件的健身追踪应用。请注意,即便是简短的 CLAUDE.md 也涵盖了全部六个核心部分:

```markdown
# Reps - Workout Tracking

**Bundle ID:** `com.941apps.Reps`
**Target:** iOS 26+
**Architecture:** SwiftUI + SwiftData
**Swift version:** 6.2

## File Structure

Reps/ ├── RepsApp.swift # App entry, model container ├── Models/ │ ├── Workout.swift # @Model: workout with exercises, date, duration │ ├── Exercise.swift # @Model: exercise with sets, reps, weight │ └── ExerciseTemplate.swift # @Model: saved exercise definitions ├── Views/ │ ├── WorkoutListView.swift # Main list of workouts │ ├── WorkoutDetailView.swift # Exercises within a workout │ ├── ExerciseRow.swift # Single exercise with inline editing │ ├── AddExerciseSheet.swift # Exercise selection from templates │ ├── NewWorkoutView.swift # Start new workout flow │ └── StatsView.swift # Progress charts and summaries ├── Managers/ │ └── WorkoutTimer.swift # Active workout timer └── Extensions/ └── Date+Extensions.swift # Formatting helpers

## Build & Test

```bash
xcodebuild -scheme Reps -destination 'platform=iOS Simulator,name=iPhone 16 Pro' build
xcodebuild -scheme Reps -destination 'platform=iOS Simulator,name=iPhone 16 Pro' test

SwiftData Relationships

  • Workout has many Exercise (cascade delete)
  • Exercise has optional ExerciseTemplate
  • ExerciseTemplate standalone (nullify on exercise delete)

Rules

  • NEVER modify .pbxproj
  • NEVER use ObservableObject — use @Observable
  • NEVER use NavigationView — use NavigationStack
  • @Model classes are already Observable — do not add @Observable macro
  • Use @Bindable for form bindings to model properties
仅 40 行 CLAUDE.md 即可描述一个 14 文件的项目。编写耗时约 10 分钟,却能节省数小时的代理调试时间。

### 真实 CLAUDE.md 示例:Starfield Destroyer(SpriteKit + Metal——32个文件)

游戏项目需要更多框架特定的上下文信息。代理需要理解场景图层级、物理碰撞类别以及游戏状态机:

```markdown
# Starfield Destroyer - Space Shooter

**Bundle ID:** `com.941apps.StarfieldDestroyer`
**Target:** iOS 26+
**Architecture:** SpriteKit + Metal post-processing + Game Center
**Swift version:** 6.2

## Game Overview

99 levels across 3 galaxies. 8 unlockable ships with different stats.
Game Center leaderboards and achievements. Metal shader post-processing
for bloom and screen effects.

## File Structure

StarfieldDestroyer/ ├── StarfieldDestroyerApp.swift # App entry, Game Center auth ├── GameScene.swift # Main game scene, update loop ├── MenuScene.swift # Title screen, ship selection ├── Entities/ │ ├── PlayerShip.swift # Player node with physics, weapons, shields │ ├── EnemyShip.swift # Enemy base class with AI behaviors │ ├── Bullet.swift # Bullet pool node │ ├── PowerUp.swift # Collectible power-ups │ └── Boss.swift # Boss enemies (levels 33, 66, 99) ├── Systems/ │ ├── LevelManager.swift # Level progression, wave spawning │ ├── PhysicsCategory.swift # UInt32 bitmask categories │ ├── CollisionHandler.swift # Contact delegate methods │ ├── ScoreManager.swift # Score tracking, multipliers │ ├── ParticleManager.swift # Explosion, trail, shield emitters │ └── AudioManager.swift # Sound effects, background music ├── UI/ │ ├── HUDNode.swift # Score, health, level display │ ├── ShipSelectView.swift # SwiftUI ship selection (UIHostingController) │ ├── GameOverView.swift # Game over screen with score submission │ └── PauseMenu.swift # Pause overlay ├── Metal/ │ ├── MetalRenderer.swift # Post-processing render pipeline │ ├── BloomShader.metal # Bloom post-process effect │ └── ShaderTypes.h # Shared uniforms (bridging header) ├── Data/ │ ├── ShipData.swift # 8 ship definitions (speed, damage, shields) │ ├── LevelData.swift # 99 level configurations │ └── AchievementData.swift # Game Center achievement definitions └── GameCenterManager.swift # Leaderboard/achievement submission

## SpriteKit Scene Hierarchy

GameScene (SKScene) ├── backgroundLayer (zPosition: -100) │ └── StarfieldNode (parallax scrolling, 3 layers) ├── gameLayer (zPosition: 0) │ ├── playerShip (zPosition: 10) │ ├── enemyContainer (zPosition: 5) │ ├── bulletPool (zPosition: 8) — pre-allocated 50 bullets │ └── powerUpContainer (zPosition: 3) ├── effectsLayer (zPosition: 50) │ └── ParticleManager (explosion + trail emitters) └── hudLayer (zPosition: 100) ├── scoreLabel (SKLabelNode) ├── healthBar (custom SKShapeNode) └── levelLabel (SKLabelNode)

## Physics Categories

```swift
struct PhysicsCategory {
    static let none:      UInt32 = 0
    static let player:    UInt32 = 0b1        // 1
    static let enemy:     UInt32 = 0b10       // 2
    static let bullet:    UInt32 = 0b100      // 4
    static let powerUp:   UInt32 = 0b1000     // 8
    static let shield:    UInt32 = 0b10000    // 16
    static let bossBullet:UInt32 = 0b100000   // 32
}

// Contact pairs:
// player + enemy → damage
// player + powerUp → collect
// bullet + enemy → destroy
// player + bossBullet → damage

Game State Machine

.menu  .playing  .paused  .playing
                  .gameOver  .menu
                  .bossIntro  .playing
                  .levelComplete  .playing (next level)

Metal Post-Processing

  • Bloom shader: BloomShader.metal — multi-pass Gaussian blur + additive blend
  • Uniforms: PostProcessUniforms { float intensity; float threshold; float2 resolution; }
  • Applied after SpriteKit renders each frame via SKView.presentScene(:transition:)
  • DO NOT modify Metal shaders without testing on device

Build & Test

xcodebuild -scheme StarfieldDestroyer -destination 'platform=iOS Simulator,name=iPhone 16 Pro' build
xcodebuild -scheme StarfieldDestroyer -destination 'platform=iOS Simulator,name=iPhone 16 Pro' test

## 规则

- 绝对不要修改 .pbxproj
- 绝对不要修改 PhysicsCategory 位掩码(会破坏所有碰撞检测)
- 在未理解渲染顺序的情况下,绝对不要更改场景层级的 z 排序
- 绝对不要在未同步更新 Swift  Metal 引用的情况下修改 ShaderTypes.h
- 添加新敌人时应继承 EnemyShip 子类,而非直接修改原类
- 子弹池化:通过 removeFromParent() + 重新添加来回收,绝不重新分配
- Game Center:提交分数前务必检查 isAuthenticated

实际的 CLAUDE.md 示例:amp97(Metal + 音频可视化 — 41 个文件)

Metal 项目需要最详细的框架上下文,因为代理无法验证视觉输出:

# amp97 - Audio Visualizer

**Bundle ID:** `com.941apps.amp97`
**Target:** iOS 26+
**Architecture:** Metal render pipeline + AVAudioEngine analysis
**Swift version:** 6.2

## Architecture

Audio Input (microphone/file) → AVAudioEngine tap → FFT (vDSP) → Frequency/amplitude buffers → Metal compute shader (analysis) → Metal render pipeline (visualization) → CADisplayLink (60fps) → MTKView

## File Structure

amp97/ ├── amp97App.swift # App entry ├── Audio/ │ ├── AudioEngine.swift # AVAudioEngine setup, tap installation │ ├── FFTProcessor.swift # vDSP FFT, frequency bin extraction │ ├── AudioBuffer.swift # Ring buffer for audio data │ └── MicrophoneManager.swift # Microphone permission, session config ├── Rendering/ │ ├── MetalView.swift # MTKView wrapper for SwiftUI │ ├── Renderer.swift # Main render loop, pipeline state │ ├── ShaderLibrary.swift # Compiled shader management │ ├── BufferManager.swift # Triple-buffered uniform updates │ └── TextureManager.swift # Offscreen render targets ├── Shaders/ │ ├── Shaders.metal # Vertex + fragment shaders │ ├── AudioCompute.metal # Audio analysis compute kernel │ ├── PostProcess.metal # Bloom, color grading │ └── ShaderTypes.h # Shared uniforms (bridging header) ├── Visualizations/ │ ├── WaveformViz.swift # Oscilloscope-style waveform │ ├── SpectrumViz.swift # Frequency spectrum bars │ ├── CircularViz.swift # Radial visualization │ └── VizSelector.swift # Visualization switching ├── Views/ │ ├── MainView.swift # Full-screen viz with overlays │ ├── ControlsOverlay.swift # Play/pause, viz selection, gain │ └── SettingsView.swift # Audio source, sensitivity └── Extensions/ ├── SIMD+Extensions.swift # Vector math helpers └── Color+Metal.swift # UIColor → float4 conversion

## Metal Pipeline

### Uniforms (ShaderTypes.h)
```c
typedef struct {
    float time;
    float2 resolution;
    float audioLevel;       // 0.0-1.0 RMS amplitude
    float frequencyBins[64]; // FFT output, normalized
    float4x4 transform;
} Uniforms;

Render Pipeline

  1. Compute pass: AudioCompute.metal processes FFT data → texture
  2. Render pass: Shaders.metal reads texture + uniforms → visualization
  3. Post-process pass: PostProcess.metal applies bloom → final output

Buffer Management

  • Triple buffering with DispatchSemaphore(value: 3)
  • Uniforms updated per-frame on CPU, consumed by GPU 1-2 frames later
  • Audio data ring buffer: 4096 samples, lock-free single producer/consumer

Rules

  • NEVER modify ShaderTypes.h without updating BOTH Swift and Metal sides
  • NEVER exceed 64 frequency bins (fixed buffer size in shader)
  • NEVER test Metal visual output in simulator — device only
  • NEVER modify the audio engine tap format (48kHz, mono, float32)
  • Triple buffer discipline: always signal semaphore in completion handler
  • Audio session: .playAndRecord category with .defaultToSpeaker option
### 根据项目规模调整 CLAUDE.md 的详细程度

合适的细节层级取决于文件数量和框架复杂度

| 项目规模 | CLAUDE.md 深度 | 示例 |
|---------|----------------|---------|
| **小型< 20 个文件** | 项目概述 + 文件列表 + 规则 | Reps14 个文件):基本 SwiftData 模式构建命令禁止事项 |
| **中型20-40 个文件** | + 框架上下文 + 关键模式 | TappyColor30 个文件):SpriteKit 场景层级物理类别游戏循环 |
| **大型40+ 个文件** | + 架构图 + 关系映射 + 多目标信息 | Return63 个文件):跨平台架构会话同步图各平台差异 |
| **专业型Metal/GPU** | + 管线图 + 共享类型定义 + 缓冲区布局 | amp9741 个文件):渲染管线阶段Uniform 结构体缓冲区管理 |

过度文档化的成本几乎为零代理会跳过不需要的内容),而文档不足的代价则很高代理会自行创造与代码库冲突的模式)。

### CLAUDE.md 检查清单

在为 iOS 项目创建或审核 CLAUDE.md 请参考以下清单

- [ ] 已指定 Bundle ID 和部署目标
- [ ] 已注明 Swift 版本和架构模式
- [ ] 文件结构包含内联用途说明
- [ ] 构建命令使用正确的 scheme  destination
- [ ] 测试命令使用正确的 scheme  destination
- [ ] 已注明 MCP 偏好"优先使用 build_sim 而非 xcodebuild"
- [ ] @Observable 规则绝不使用 ObservableObject
- [ ] NavigationStack 规则绝不使用 NavigationView
- [ ] .pbxproj 禁止修改规则
- [ ] 框架特定上下文HealthKit 权限SwiftData 关系SpriteKit 层级Metal 管线
- [ ] 已记录平台可用性守卫#if canImport#if os
- [ ] 已记录关键单例和共享模式
- [ ] 已记录已知限制或注意事项

---

## 第一次代理会话

配置好 MCP 并在项目中放置 CLAUDE.md 以下是一个高效首次会话的完整演练此示例使用 Claude Code CLI但工作流程适用于任何运行时

### 步骤 1验证代理能否识别您的项目

You: Summarize this project. What scheme should I build with?

Claude: [reads CLAUDE.md] [calls discover_projs via MCP] [calls list_schemes via MCP]

    This is Return, a zen meditation timer for iOS 26+, watchOS, and tvOS.
    Available schemes: Return, ReturnWatch, ReturnTV, ReturnTests.
    Primary scheme for iOS: Return.
如果代理未引用 CLAUDE.md 的内容,请检查该文件是否位于项目根目录(与 `.xcodeproj` 或 `Package.swift` 同级目录)。

### 步骤 2:运行健康检查构建

You: Build the Return scheme for iOS simulator and report results.

Claude: [calls list_sims — finds iPhone 16 Pro on iOS 26.2] [calls boot_sim — boots the simulator] [calls build_sim — builds the project]

    Build succeeded. 63 source files compiled.
    2 warnings:
    - HomeView.swift:132 — UIScreen.main deprecated in iOS 26.0
    - LogWaterIntent.swift:61 — Result of try? is unused
    0 errors.
### 步骤 3:运行测试

You: Run all tests and report pass/fail.

Claude: [calls test_sim]

    12 tests executed:
    ✓ TimerManagerTests (5/5 passed)
    ✓ SettingsTests (4/4 passed)
    ✓ ConstantsTests (3/3 passed)
    All tests passed.
### 步骤 4:实现一个功能

You: Add a new “Rain” theme to the theme system. Follow the existing pattern in Theme.swift and ThemeManager.swift. Include a rain ambient sound. Build and test after implementation.

Claude: [reads Theme.swift — understands Theme struct pattern] [reads ThemeManager.swift — understands theme registration] [reads existing theme definitions] [adds Rain theme to Theme.swift following existing pattern] [registers Rain theme in ThemeManager.swift] [calls build_sim — build succeeds] [calls test_sim — all tests pass]

    Added Rain theme:
    - Theme.swift: new `static let rain` with video, cover, ambient
    - ThemeManager.swift: added to `allThemes` array
    - Build: success (0 errors, 2 existing warnings)
    - Tests: 12/12 passed

    Note: You'll need to add rain_ambient.wav to the project
    and add the new Theme.swift changes to the Xcode target manually
    (I did not modify .pbxproj).
代理在最后提示未修改 .pbxproj正是 CLAUDE.md 中规则生效的体现如果没有该规则代理会尝试修改项目文件很可能导致文件损坏

## 智能体在iOS开发中的优势

以下是智能体能够持续产出正确可投产代码且仅需少量人工审查的任务类型

### SwiftUI视图与修饰符

智能体对SwiftUI声明式语法具有深度的模式识别能力视图组合修饰符链状态绑定和布局——这些都能很好地映射到智能体的训练数据因为SwiftUI的API接口文档完善模式高度一致

**智能体表现出色的场景**
- 根据描述构建新视图"创建一个包含X、Y、Z开关的设置页面"
- 应用修饰符链(`.glassEffect()`、`.sensoryFeedback()`、`.navigationTitle()`)
- 布局模式转换VStack转LazyVGridList转ScrollView
- 实现`@Bindable`表单绑定到SwiftData模型
- 构建包含示例数据的预览提供器

**能产出优质结果的提示词示例**

Create a SettingsView that matches the existing pattern in SettingsSheet.swift. Include toggles for: - Enable haptic feedback (Settings.shared.hapticsEnabled) - Enable HealthKit logging (Settings.shared.healthKitEnabled) - Show session history (navigation link to SessionHistoryView)

Use Liquid Glass styling with .glassEffect() on section backgrounds. Follow the @Observable pattern, not ObservableObject.

具体性至关重要。"创建一个设置视图"只会产出泛泛的结果,而"创建一个与SettingsSheet.swift中现有模式一致的SettingsView"则能产出与代码库风格统一的输出。

### SwiftData模型与查询

智能体能可靠地处理SwiftData的`@Model`宏、关系定义和`@Query`模式。该框架的声明式特性(类似Django ORM或SQLAlchemy)与智能体在众多代码库中见过的模式高度契合。

**智能体表现出色的场景:**
- 定义带关系的`@Model`
- 编写包含排序描述符和谓词的`@Query`
- 通过`modelContext`实现CRUD操作
- 制定跨架构版本的迁移方案
- 预览数据和测试夹具

**需要额外指导的场景:**
- 复杂的`#Predicate`表达式(SwiftData的谓词DSL存在一些限制,智能体并不总能识别——建议在CLAUDE.md中记录已知限制)
- CloudKit同步配置(通过SwiftData可自动完成,但智能体可能会尝试实现手动同步)

### 单元测试

智能体编写的iOS项目单元测试质量始终很高。它深谙XCTest模式、异步测试方法以及setup/teardown生命周期。

Write unit tests for TimerManager covering: 1. Initial state is .stopped 2. start() transitions to .running 3. pause() transitions to .paused 4. reset() returns to .stopped with original duration 5. Timer counts down correctly (test with 3-second duration)

智能体会生成结构良好的XCTest用例,包含`setUp()``tearDown()`方法、恰当的断言,以及针对计时器测试的异步处理。

### 重构与模式应用

智能体擅长机械化重构:将视图提取为组件、将`ObservableObject`转换为`@Observable`、从`NavigationView`迁移到`NavigationStack`,以及在多个文件中统一应用一致的模式。

Refactor all views in the Views/ directory to use @Observable instead of ObservableObject. Update @StateObject to @State, @ObservedObject to direct property access, and @Published to plain properties.

智能体会系统地逐一处理每个文件,正确应用转换,同时保持现有功能不受影响。这是高杠杆率的工作——手动编辑可能需要一小时的重构,借助智能体几分钟即可完成,且准确率极高。

### 通过MCP诊断构建错误

借助结构化的MCP输出,智能体诊断构建错误的速度超过大多数开发者。它能读取错误JSON,精确定位文件和行号,理解错误信息,并应用修复——通常一轮即可完成。

**智能体可自主修复的错误:**
- 缺少导入
- 类型不匹配
- 协议一致性缺失
- 已弃用的API用法(附带替代方案)
- 缺少必需的初始化参数
- 访问控制违规

**需要人工协助的错误:**
- 类型解析歧义(多个模块定义了相同类型)
- 复杂的泛型约束失败
- 宏展开错误(智能体无法查看展开后的宏输出)

### 模拟器管理

智能体通过MCP能够很好地处理模拟器生命周期:

Boot an iPhone 16 Pro simulator on iOS 26, install the app, and take a screenshot.

智能体会调用`list_sims`查找可用运行时,`boot_sim`启动模拟器,`build_sim`构建并安装应用,`screenshot`截取屏幕——所有操作均通过结构化的MCP调用完成。

---

## AI 智能体在 iOS 开发中的短板

坦诚盘点智能体力所不及之处。明确这些边界,才能避免无谓的挫败感和 token 浪费。

### .pbxproj 文件修改——绝对禁区

这是 iOS 智能体开发中最重要的一条铁律。`.pbxproj` 文件是 Xcode 的项目配置文件——一种带有 UUID 引用、构建阶段列表和目标成员关系的结构化文本文件。名义上可读,但对 AI 智能体而言几乎无法正确解析。

**智能体为何无法处理 .pbxproj:**
- 该文件使用自定义格式(非 JSON、非 YAML、非 XML),且位置具有语义意义
- 每个条目都通过 UUID 交叉引用——添加一个文件需要同时更新 3  5 个不同的区段
- 一个字符的错位就会导致整个项目文件损坏
- Xcode  .pbxproj 的合并冲突处理本就脆弱——智能体的编辑只会雪上加霜

**智能体编辑 .pbxproj 后会发生什么:**
1. 编辑看似成功(智能体报告"文件已更新"
2. Xcode 拒绝打开项目("项目文件已损坏"
3. 您需要花 15  60 分钟从 git 历史中恢复
4. 从此学会添加 PreToolUse 钩子(参见[钩子](#hooks-for-ios-development))

**正确的工作流程:** 智能体创建 Swift 文件,您手动将其添加到 Xcode 项目中(拖入 Xcode,或通过 File > Add Files)。每个文件只需 5 秒,却能省去数小时的恢复工作。

**对于 Swift Package Manager 项目:** 此限制的影响较小。`Package.swift` 是标准的 Swift 文件,智能体可以可靠地编辑。如果项目完全使用 SPM(不依赖 .xcodeproj),智能体可以管理完整的项目结构。

### 复杂的 Interface Builder / Storyboard 编辑

如果项目使用 Interface Builder(`.xib` 文件)或 Storyboard(`.storyboard` 文件),智能体无法进行有效编辑。这些是包含自动生成的 UUID、约束引用和 outlet 连接的 XML 文件,设计初衷就是用于可视化编辑,而非文本编辑。

**应对策略:** 新视图一律使用 SwiftUI。如果项目中有遗留的 Interface Builder 文件,保持原样不动,新的 UI 全部用 SwiftUI 构建。

### 性能优化

智能体能写出正确的代码,但未必是高性能的代码。它们无法对应用进行性能分析、识别瓶颈或测量帧率。性能优化需要:

1. Instruments 性能分析(可视化工具,智能体无法访问)
2. 了解特定设备的 GPU/CPU 特性
3. 基于度量结果的迭代式调优

**具体表现:**
- Metal 着色器优化(智能体能写出合法的 Metal 代码,但无法测量 GPU 帧时间)
- SwiftUI 视图 body 复杂度(智能体创建的深层嵌套视图会导致重绘开销)
- Core Data / SwiftData 查询优化(智能体写出的查询语法正确,但在大数据集上可能较慢)

**应对策略:** 让智能体负责实现,手动使用 Instruments 进行性能分析,然后将您识别出的具体优化方案交给智能体执行。

### 代码签名与配置文件

智能体在调试代码签名问题时,能力仅限于读取错误信息。配置文件管理、证书创建、权限配置以及 App Store 提交,这些本质上都是需要人工操作的流程,涉及 Apple Developer 门户、钥匙串访问和 Xcode 的签名界面。

**智能体看到的是:** "Signing for 'Return' requires a development team."

**智能体看不到的是:** 证书是否过期、配置文件是否包含该设备、Bundle ID 是否与 App ID 匹配、权限文件是否正确。

**应对策略:** 所有签名事务都在 Xcode  Signing & Capabilities 标签页中处理,不要让智能体调试签名问题。

### 复杂的 Metal 着色器调试

智能体能写出语法正确的 Metal Shading Language(MSL),但无法验证视觉输出或调试 GPU 端问题。Metal 着色器在 GPU 上执行——智能体没有任何反馈机制来判断着色器是否产生了正确的视觉效果。

**智能体能做的 Metal 工作:**
- 根据描述编写顶点和片段着色器
-  Swift 中搭建 Metal 渲染管线
- 创建用于数据并行操作的计算着色器
- 修复 `.metal` 文件中的编译错误

**智能体做不到的 Metal 工作:**
- 验证着色器输出的视觉正确性
- 调试 GPU 性能(帧时间、占用率、显存带宽)
- 诊断视觉伪影(色带、精度问题、色彩空间错误)
- 在不同 GPU 架构上测试(A 系列与 M 系列的行为差异)

**应对策略:** 在真机上测试 Metal 着色器。模拟器的 Metal 实现无法代表设备 GPU 的真实行为。使用 Xcode  GPU Frame Capture 进行可视化调试。

### 视觉布局验证

智能体看不到应用的 UI。它们编写 SwiftUI 布局代码并能验证编译通过,但无法判断最终呈现的画面是否正确。视图偏移 10 像素、字重不对、元素重叠——这些问题不会产生构建错误,也能通过所有逻辑测试。

**应对策略:** 肉眼审查 UI 变更。在 Xcode 中使用 SwiftUI Previews(或通过 Apple MCP  `RenderPreview` 进行无头渲染)验证布局。可以考虑使用 swift-snapshot-testing 等库进行快照测试,实现自动化的视觉回归检测。

---

## iOS 开发中的 Hooks

Hooks 是在代理工作流特定节点确定性执行的 shell 命令。它们是强制执行机制——区别在于"请不要编辑 .pbxproj"(代理可能忽略的建议)和"你无法编辑 .pbxproj"(硬性拦截)。

关于 hook 系统的背景知识,请参阅 [Claude Code hooks 指南](/blog/claude-code-hooks-tutorial)。本节重点介绍 iOS 特有的 hook 模式。

### PreToolUse:拦截 .pbxproj 写入

这是所有 iOS 项目中最重要的 hook。它会阻止代理写入 `.pbxproj` 文件、`.xcodeproj/` 目录以及其他 Xcode 管理的文件:

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "bash -c 'INPUT=$(cat); FP=$(echo \"$INPUT\" | jq -r \".tool_input.file_path // empty\"); if echo \"$FP\" | grep -qE \"\\.(pbxproj|xcworkspace|xib|storyboard)$|xcodeproj/|xcworkspace/\"; then echo \"BLOCKED: Do not modify Xcode project files. Create Swift files and add to Xcode manually.\" >&2; exit 2; fi'"
      }
    ]
  }
}

将此配置放在项目根目录的 .claude/settings.json 中,或放在 ~/.claude/settings.json 中以实现全局保护。

工作原理: 当代理尝试对匹配模式的文件使用 Edit 或 Write 工具时,hook 会运行并检测文件路径,将警告信息输出到 stderr,然后以退出码 2 退出(这会阻止工具的使用)。代理收到错误消息后会调整策略。

拦截范围: - 直接编辑 .pbxproj - .xcodeproj/.xcworkspace/ 目录内的任何文件 - Interface Builder 文件(.xib.storyboard

PostToolUse:保存时自动运行 SwiftFormat

每当代理写入或编辑 Swift 文件时,自动进行格式化:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "bash -c 'INPUT=$(cat); FP=$(echo \"$INPUT\" | jq -r \".tool_input.file_path // empty\"); if echo \"$FP\" | grep -qE \"\\.swift$\"; then swiftformat \"$FP\" --quiet 2>/dev/null; fi'"
      }
    ]
  }
}

前置要求: 需要安装 SwiftFormat(brew install swiftformat)。

为什么重要: 代理生成的 Swift 代码语法正确,但格式规范的一致性不够稳定。SwiftFormat 会统一缩进、大括号位置和 import 排序。保存时自动格式化意味着代理修改的每个 Swift 文件在呈现给你之前都已完成格式化。

可选:在项目根目录添加 .swiftformat 配置文件,自定义格式化规则:

# .swiftformat
--indent 4
--allman false
--stripunusedargs closure-only
--importgrouping testable-bottom
--header strip

PostToolUse:自动运行 SwiftLint

如果使用了 SwiftLint,可在每次编辑 Swift 文件后自动运行:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "bash -c 'INPUT=$(cat); FP=$(echo \"$INPUT\" | jq -r \".tool_input.file_path // empty\"); if echo \"$FP\" | grep -qE \"\\.swift$\"; then swiftlint lint --path \"$FP\" --quiet 2>/dev/null || true; fi'"
      }
    ]
  }
}

|| true 可以防止 lint 警告阻断代理运行。如果希望 lint 违规直接阻断,去掉即可。

PostToolUse:修改后自动构建

若需更紧密的反馈循环,可在每次 Swift 文件变更后触发构建:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "bash -c 'INPUT=$(cat); FP=$(echo \"$INPUT\" | jq -r \".tool_input.file_path // empty\"); if echo \"$FP\" | grep -qE \"\\.swift$\"; then xcodebuild -scheme Return -destination \"platform=iOS Simulator,name=iPhone 16 Pro\" build 2>&1 | tail -5; fi'"
      }
    ]
  }
}

注意: 此操作开销较大。每次文件编辑都会触发一次构建,应谨慎使用——最适合调试阶段需要即时构建反馈的场景。在常规开发中,建议让代理准备就绪后通过 MCP 手动触发构建。

PreToolUse:拦截权限配置文件修改

保护 entitlements 文件,防止代理意外修改:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "bash -c 'INPUT=$(cat); FP=$(echo \"$INPUT\" | jq -r \".tool_input.file_path // empty\"); if echo \"$FP\" | grep -qE \"\\.entitlements$\"; then echo \"BLOCKED: Do not modify entitlements files without explicit permission.\" >&2; exit 2; fi'"
      }
    ]
  }
}

完整的 iOS Hook 配置

以下是我在所有 iOS 项目中使用的完整 .claude/settings.json 配置:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "bash -c 'INPUT=$(cat); FP=$(echo \"$INPUT\" | jq -r \".tool_input.file_path // empty\"); if echo \"$FP\" | grep -qE \"\\.(pbxproj|xcworkspace|xib|storyboard|entitlements)$|xcodeproj/|xcworkspace/\"; then echo \"BLOCKED: Do not modify Xcode-managed files. Create Swift files and add manually.\" >&2; exit 2; fi'"
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "bash -c 'INPUT=$(cat); FP=$(echo \"$INPUT\" | jq -r \".tool_input.file_path // empty\"); if echo \"$FP\" | grep -qE \"\\.swift$\"; then swiftformat \"$FP\" --quiet 2>/dev/null; fi'"
      }
    ]
  }
}

这套配置提供两项保障: 1. 代理无法破坏 Xcode 项目文件(PreToolUse 拦截) 2. 代理修改的每个 Swift 文件都会自动格式化(PostToolUse 格式化)


适合智能体协作的架构模式

并非所有 Swift 架构都同样适合智能体协作。以下模式效果最佳,因为它们显式、一致,且在训练数据中有充分的表征。

@Observable(禁用 ObservableObject)

iOS 26+ 项目应统一使用 @Observable。这既是现代范式,也是最适合智能体的范式:

// CORRECT — @Observable
@Observable
@MainActor
final class TimerManager {
    var timeRemaining: TimeInterval = 0
    var state: TimerState = .stopped

    func start() {
        state = .running
        // ...
    }
}

// In a view:
struct TimerView: View {
    @State private var timer = TimerManager()

    var body: some View {
        Text(timer.timeRemaining, format: .number)
    }
}
// WRONG — ObservableObject (deprecated pattern)
class TimerManager: ObservableObject {
    @Published var timeRemaining: TimeInterval = 0
    @Published var state: TimerState = .stopped
}

// WRONG — @StateObject (deprecated pattern)
struct TimerView: View {
    @StateObject private var timer = TimerManager()
}

为何 @Observable 更适合智能体: 该模式更简洁(无需 @Published 注解),所有权模型更清晰(@State 代替了 @StateObject@ObservedObject 的选择困境),智能体使用时产生的错误也更少,因为活动部件更少。

务必在 CLAUDE.md 中标注: 即使目标平台为 iOS 26,智能体偶尔仍会回退到训练数据中的 ObservableObject 模式。明确禁止可以避免这种情况。

// CORRECT
NavigationStack {
    List(items) { item in
        NavigationLink(value: item) {
            ItemRow(item: item)
        }
    }
    .navigationDestination(for: Item.self) { item in
        ItemDetailView(item: item)
    }
}

// WRONG
NavigationView {
    List(items) { item in
        NavigationLink(destination: ItemDetailView(item: item)) {
            ItemRow(item: item)
        }
    }
}

NavigationStack 自 iOS 16+ 起可用,是新代码中唯一应使用的导航模式。类型安全的 navigationDestination(for:) 模式可防止智能体创建错误的导航链接。

使用 SwiftData 进行持久化

SwiftData 模型是智能体辅助开发中最简洁的持久化方案:

@Model
final class GroceryItem {
    var name: String
    var quantity: Int
    var isCompleted: Bool
    var category: Category?
    var list: GroceryList?

    init(name: String, quantity: Int = 1) {
        self.name = name
        self.quantity = quantity
        self.isCompleted = false
    }
}

智能体使用 SwiftData 的关键规则: 1. @Model 类自动具备 Observable 特性——不要重复添加 @Observable 2. 表单绑定使用 @Bindable@Bindable var item: GroceryItem 3. 视图中使用 @Query 实现响应式数据:@Query var items: [GroceryItem] 4. 非视图代码中使用 modelContext.fetch() 5. 关系删除需显式指定规则:.cascade.nullify.deny

Swift 6.2 并发

新项目应采用 Swift 6.2 严格并发模式:

// Actor isolation for shared mutable state
@MainActor
@Observable
final class DataManager {
    var items: [Item] = []

    func loadItems() async throws {
        let fetched = try await api.fetchItems()
        items = fetched  // Safe: @MainActor isolated
    }
}

// Sendable conformance for cross-actor transfers
struct Item: Sendable, Identifiable {
    let id: UUID
    let name: String
    let createdAt: Date
}

并发相关的智能体指导: - 所有视图模型标记为 @MainActor(防止数据竞争警告) - 所有异步操作使用 async/await(禁用回调式完成处理器) - 值类型遵循 Sendable 以支持跨 Actor 传递 - 视图中使用 Task { } 进行异步初始化 - 仅在经过性能测量确认有必要时才使用 nonisolated

Liquid Glass 设计系统(iOS 26+)

iOS 26 引入了 Liquid Glass 设计系统。在提供明确指导后,智能体能很好地处理它:

// Glass effect on containers
VStack {
    // content
}
.glassEffect()

// Glass effect with tint
Button("Action") { }
    .glassEffect(.regular.tint(.blue))

// Glass effect on navigation bars (automatic in iOS 26)
NavigationStack {
    // content
}
// Navigation bar automatically uses glass material

// Custom glass shapes
RoundedRectangle(cornerRadius: 16)
    .fill(.ultraThinMaterial)
    .glassEffect()

在 CLAUDE.md 中包含以下内容: “在分区背景和卡片容器上使用 .glassEffect()。iOS 26 中导航栏会自动采用玻璃材质。不要用自定义材质手动模拟玻璃效果——使用系统修饰符。”


框架专项指南

每个 Apple 框架都有与智能体相关的特殊考量。本节涵盖 8 款应用所使用的框架。

HealthKit

使用该框架的应用: Return、Water

HealthKit 需要谨慎处理权限请求和平台兼容性判断:

// Always check availability and authorization
import HealthKit

@MainActor
@Observable
final class HealthKitManager {
    private let store = HKHealthStore()
    var isAuthorized = false

    func requestAuthorization() async {
        guard HKHealthStore.isHealthDataAvailable() else { return }

        let types: Set<HKSampleType> = [
            HKQuantityType(.dietaryWater),
            HKCategoryType(.mindfulSession)
        ]

        do {
            try await store.requestAuthorization(toShare: types, read: types)
            isAuthorized = true
        } catch {
            // User denied — do not retry automatically
        }
    }
}

HealthKit 的智能体规则: - 始终使用 HKHealthStore.isHealthDataAvailable() 进行可用性检查 - 切勿假定已获授权——每次写入前都要验证 - 多平台代码使用 #if canImport(HealthKit)(HealthKit 在 tvOS 上不可用) - 切勿在本地存储超出 HealthKit 提供范围的健康数据 - 在 Info.plist 中同时包含 NSHealthShareUsageDescriptionNSHealthUpdateUsageDescription

SpriteKit

使用该框架的应用: TappyColor、Starfield Destroyer

SpriteKit 的场景图模型需要对智能体进行明确指导:

## SpriteKit Rules

- Scene hierarchy is a tree of SKNodes with zPosition ordering
- Physics bodies use category bitmasks (UInt32) for collision detection
- Node pooling: pre-allocate reusable nodes (bullets, particles)
- Never add nodes directly to the scene — use layer nodes for organization
- Update loop: `update(_ currentTime:)` runs every frame — keep it fast
- Actions: use SKAction sequences for animations, not manual property updates
- Textures: use texture atlases for performance (.atlas directories)

智能体在 SpriteKit 中的优势: - 创建 SKAction 序列和组合 - 设置物理体和碰撞检测 - 实现游戏状态机 - 构建 HUD 覆盖层

智能体在 SpriteKit 中的短板: - 性能敏感的游戏循环(智能体会在每帧中引入不必要的计算开销) - 复杂物理模拟(自定义物理引擎在精度上优于 SKPhysicsBody) - 粒子效果调优(需要视觉迭代,属于感官层面的工作)

Metal

使用该框架的应用: amp97、Water、Starfield Destroyer

Metal 是智能体最容易出错的框架。GPU 编程模型与 CPU 端的 Swift 有本质区别,且智能体无法验证视觉输出。

## Metal Rules

- Shared types between Swift and Metal go in a bridging header (ShaderTypes.h)
- Triple buffer in-flight frames (semaphore with value 3)
- Test shaders on DEVICE, not simulator (Metal behavior differs)
- Compute shaders: threadgroup size must divide evenly into grid size
- Fragment shaders: output color must be in correct color space (sRGB or linear)
- DO NOT optimize shaders without Instruments GPU profiling data

Metal 项目的 CLAUDE.md 应包含以下内容: - Uniforms 结构体定义(Swift 与 MSL 共享) - 渲染管线状态的设置模式 - Buffer 索引及其用途 - 现有着色器清单及各自功能 - 已知精度问题(half 与 float)

Live Activities

使用该框架的应用: Return

Live Activities 需要特定的配置,文档化后智能体能很好地处理:

## Live Activities

- ActivityAttributes defined in `TimerActivityAttributes.swift`
- ActivityKit framework: `import ActivityKit`
- Widget extension: `ReturnWidgets/ReturnLiveActivity.swift`
- Start: `Activity<TimerActivityAttributes>.request(attributes:content:)`
- Update: `activity.update(ActivityContent(state:staleDate:))`
- End: `activity.end(ActivityContent(state:staleDate:), dismissalPolicy:)`
- Push token: register for updates via `activity.pushTokenUpdates`

Game Center

使用该框架的应用: Starfield Destroyer

## Game Center

- Authentication: `GKLocalPlayer.local.authenticateHandler`
- Leaderboards: `GKLeaderboard.submitScore(_:context:player:leaderboardIDs:completionHandler:)`
- Achievements: `GKAchievement.report(_:withCompletionHandler:)` (takes `[GKAchievement]` array)
- Always check `GKLocalPlayer.local.isAuthenticated` before submitting
- Handle authentication failure gracefully (offline play must work)

多平台开发模式

Return 横跨 iOS、watchOS 和 tvOS 三个平台。使用代理进行多平台开发时,需要明确记录平台边界。

共享代码组织

Shared/
├── MeditationSession.swift    # Data model (all platforms)
├── SessionStore.swift         # iCloud sync (all platforms)
└── SessionHistoryView.swift   # UI (adapts per platform)

Return/                        # iOS-specific
ReturnWatch Watch App/         # watchOS-specific
ReturnTV/                      # tvOS-specific

代理规则:“如果文件位于 Shared/ 目录中,修改将影响所有平台。如果文件位于特定平台目录中,修改仅限于该平台。修改文件前,务必先确认文件所在目录。”

平台可用性守卫

// HealthKit: available on iOS and watchOS, not tvOS
#if canImport(HealthKit)
import HealthKit
// HealthKit code here
#endif

// ActivityKit: available on iOS only
#if canImport(ActivityKit)
import ActivityKit
// Live Activity code here
#endif

// WatchKit: available on watchOS only
#if os(watchOS)
import WatchKit
// Watch-specific code here
#endif

代理指引:“使用平台特定框架时,始终使用 #if canImport()#if os() 守卫。不要假设某个框架在所有构建目标上都可用。”

各平台 UI 适配

struct SessionHistoryView: View {
    @Query var sessions: [MeditationSession]

    var body: some View {
        List(sessions) { session in
            SessionRow(session: session)
        }
        #if os(tvOS)
        .focusable()
        #endif
        #if os(iOS)
        .swipeActions {
            Button("Delete", role: .destructive) {
                // delete
            }
        }
        #endif
    }
}

进阶工作流

自主构建-测试-修复循环

最强大的模式莫过于:向代理提供功能规格说明,让它自主迭代完成构建-测试-修复循环。

Implement a countdown timer that:
1. Starts from a user-selected duration (10, 20, or 30 minutes)
2. Shows remaining time with a circular progress indicator
3. Plays a bell sound on completion
4. Logs the session to HealthKit as mindful minutes

Build after each change. Fix all errors. Run tests when the build succeeds.
Continue until all tests pass and the build is clean.

代理编写代码,通过 MCP 构建项目,读取结构化错误信息,修复问题,然后重复这一过程。一个通常需要人工经历 5 到 10 次构建-报错-修复循环的功能,在单次自主循环中即可完成。

适用场景:定义明确、验收标准清晰的功能。

不适用场景:开放式功能(如”让界面更好看”)、性能敏感的代码,或任何需要视觉验证的场景。

iOS 子代理委派

Claude Code 的子代理系统同样适用于 iOS 项目:

Use a subagent to research the best approach for implementing
iCloud key-value store sync for meditation sessions across iOS,
watchOS, and tvOS. Report back with the recommended pattern.

子代理在独立的上下文窗口中探索文档和代码模式,返回总结报告,主会话再据此实施建议方案。这样可以避免研究过程占用主上下文空间。

跨应用模式复用

当多个 iOS 应用需要保持一致的设计模式时,代理可以将一个应用中的模式应用到另一个应用:

Look at how Settings.swift works in the Return project
(centralized singleton with validation). Apply the same pattern
to create a Settings.swift for the Water project.

代理读取源模式、理解其结构,然后在目标项目中创建风格一致的实现。

双代理审查(Claude + Codex)

对于关键变更,可使用来自不同模型家族的两个代理进行审查:

  1. Claude Code 编写实现代码
  2. Codex CLI 在单独的流程中进行审查
# After Claude implements the feature:
codex "Review the changes in the last commit. Focus on Swift 6.2
      concurrency correctness, SwiftData relationship integrity,
      and potential retain cycles. Report issues only — no praise."

不同的模型家族能捕获不同类别的错误。这在 Metal 着色器和并发模式方面尤为重要,因为此类场景中细微的缺陷极易引入。

双代理审查能发现而单代理审查容易遗漏的问题:

问题类型 Claude 优势 Codex 优势
SwiftData 关系循环 中等 强(GPT-4o)
@MainActor 隔离缺口 中等
Metal 缓冲区对齐 中等 中等
循环引用检测 强(Opus) 强(o3)
API 弃用感知 强(训练数据更新) 中等
并发竞态条件 强(捕获不同模式)

双代理审查的价值不在于发现更多缺陷,而在于发现不同类型的缺陷。每个模型家族在模式识别方面都有各自不同的盲区。

跨多应用批量操作

当框架或模式变更影响多个应用时:

# Update @Observable pattern across all projects
for project in BananaList Return Water Reps; do
  cd ~/Projects/$project
  claude -p "Audit all files for any remaining ObservableObject usage.
             Convert to @Observable following the pattern in CLAUDE.md.
             Build and test after changes." --dangerously-skip-permissions
done

请谨慎使用。--dangerously-skip-permissions 标志在非交互模式下是必需的,但会绕过所有安全检查。请确保 PreToolUse 钩子已就位,以保护 .pbxproj 文件。


实战案例研究

抽象的建议说起来容易。以下是来自这8个应用的具体场景,展示了AI辅助iOS开发在实践中的运作方式——包括失败的案例。

案例1:为Return添加TV应用(成功)

任务: 为Return添加tvOS目标。Return是一款冥想计时器,已有iOS和watchOS版本。TV应用需要支持Siri Remote导航、大屏UI,以及与iOS应用的设置同步。

Agent表现出色的方面: - 读取了现有的iOS TimerManager,创建了 TVTimerManager,去除了tvOS上不可用的Live Activities和HealthKit - 为Siri Remote焦点导航创建了自定义按钮样式(TVCapsuleButtonStyleTVCircleButtonStyle) - 构建了 TVStepper 组件,用+/-按钮替代了Siri Remote无法使用的滚轮选择器 - 通过App Groups(group.com.941apps.Return)实现了设置同步 - 在共享代码中添加了 #if os(tvOS) 条件编译守卫 - 通过 MCP 使用 platform=tvOS Simulator,name=Apple TV 进行构建和测试

需要我手动完成的部分: - 在Xcode中创建tvOS目标(File > New > Target > tvOS App) - 将新目标添加到Xcode项目(.pbxproj变更) - 为TV目标配置App Groups权限 - 将TV目标添加到现有scheme或创建新scheme - 手动将Agent创建的所有Swift文件添加到TV目标 - 手动测试Siri Remote导航(Agent无法评估焦点行为)

结果: 15个新Swift文件,功能完整的TV应用,大约3小时的Agent辅助工作完成。同等工作量的纯手动实现需要1-2天。Agent处理了约80%的代码,我负责了需要Xcode UI交互和手动测试的20%。

案例2:amp97中的Metal着色器调试(部分失败)

任务: 为示波器着色器添加基于能量的强度系统,使可视化效果能随音频能量脉动。

事件经过: 1. Agent编写了有效的Metal着色器修改,添加了 uEnergy uniform和HDR色调映射 2. 代码编译无错误 3. 在设备上运行时,可视化完全变白——强度系数高了10倍(3.5而非正确的0.30) 4. Agent无法看到白屏,因此没有任何反馈信号 5. 我通过目视发现了问题,要求Agent降低系数 6. Agent降低了系数,但整体能量状态机过于复杂,以不同方式破坏了可视化器 7. 最终完全回滚——两个提交(67959edcda4830)在 869d914 中被回滚

教训: Metal着色器是Agent辅助开发中最困难的领域,因为反馈循环是断裂的。Agent可以验证语法(能编译)和语义(类型正确),但无法验证输出(视觉效果是否正确)。任何改变视觉行为的着色器修改都需要人工在设备上验证。

此后我在CLAUDE.md中添加的内容: “未经极其审慎的系数测试,不要尝试对示波器着色器进行能量状态修改。此前的尝试因系数高出10倍而导致可视化器崩溃。”

案例3:Banana List中的SwiftData迁移(成功)

任务: 将数据模型从V1迁移到V2,为 GroceryItem 添加 quantity 字段,并新增带关系的 Category 模型。

Agent的工作: 1. 读取现有V1模型定义 2. 创建包含新字段和关系的V2模型定义 3. 编写符合 SchemaMigrationPlan 协议的 GroceryMigrationPlan 4. 实现 V1toV2 迁移阶段:设置默认值 quantity: 1category: nil 5. 更新所有视图以支持新字段 6. 更新 SampleData.swift 用于预览 7. 通过 MCP 构建并运行测试——全部通过 8. 创建迁移专用的单元测试

关键因素: Agent之所以成功,是因为SwiftData迁移遵循了定义明确的协议模式,这在Apple文档和训练数据中有充分体现。CLAUDE.md中明确记录了V1模型,使Agent清楚了解迁移的起点。

案例4:Return中的iCloud会话同步(成功但复杂)

任务: 实现跨设备冥想会话记录。在Apple TV或Mac上完成的会话应同步到iPhone,用于HealthKit记录。

Agent的产出:

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
    tvOS              Mac              Watch     
 TVTimerMgr        TimerMgr          WatchTimer  
└──────┬──────┘     └──────┬──────┘     └──────┬──────┘
                                             
       └───────────────────┼───────────────────┘
                           
                           
              ┌────────────────────────┐
                   SessionStore       
                (iCloud Key-Value)    
              └───────────┬────────────┘
                          
                          
              ┌────────────────────────┐
                iPhone (on foreground)
                 Write to HealthKit  
              └────────────────────────┘

Agent的具体工作: 1. 创建 MeditationSession 数据模型,包含UUID、日期、时长、来源设备和HealthKit同步状态 2. 构建 SessionStore 单例,管理 NSUbiquitousKeyValueStore 以实现iCloud同步 3. 实现合并冲突解决(基于UUID去重) 4. 添加 SessionHistoryView,支持平台特定适配(iOS滑动删除,tvOS焦点导航) 5. 接入iPhone端的HealthKit同步,处理来自其他设备的会话

需要迭代的部分: 初始实现未处理iPhone应用在后台启动的情况(没有前台通知触发同步)。Agent需要明确指导:”使用 NSUbiquitousKeyValueStore.didChangeExternallyNotification 在后台KV变更时触发同步。”给出提示后,实现即刻正确。

教训: 当架构描述清晰时,Agent能够很好地处理多平台架构模式。iCloud同步模式虽非简单,但遵循了Apple的文档化模式,Agent能够理解。边界情况(后台同步)则需要人工的领域知识,因为相关文档较为匮乏。

案例5:Starfield Destroyer中的Game Center集成(成功)

任务: 为太空射击游戏添加Game Center排行榜和成就系统。

Agent表现出色的方面: - 在应用入口点实现了 GKLocalPlayer.local.authenticateHandler - 创建了 GameCenterManager,包含分数提交和成就上报方法 - 在所有Game Center操作前添加了认证状态检查 - 优雅处理了离线情况(无Game Center时正常游戏,重新连接后补交数据) - 创建了与8艘飞船进阶系统匹配的成就定义

需要手动完成的部分: - 在App Store Connect中创建排行榜和成就(网页后台,Agent无法访问) - 在Xcode中配置Game Center权限 - 使用沙箱Game Center账号测试(需要在设备上手动登录)


项目生命周期中的Agent协作

启动新iOS项目

使用Agent辅助启动新项目的最佳工作流:

第一阶段:人工准备(15-30分钟) 1. 创建Xcode项目(File > New > Project) 2. 配置签名和能力 3. 设置部署目标和支持的设备 4. 添加所需权限(HealthKit、Game Center等) 5. 创建初始CLAUDE.md,写明项目定位和规则

第二阶段:Agent实现(数小时至数天) 1. Agent创建数据模型(SwiftData、Core Data或普通结构体) 2. Agent按照文档中的模式构建视图 3. Agent在Manager/Service类中实现业务逻辑 4. Agent编写单元测试 5. 通过 MCP 进行构建-测试-修复循环(自主运行)

第三阶段:人工集成(30-60分钟) 1. 将Agent创建的文件添加到Xcode目标 2. 验证签名和权限 3. 在真机上测试 4. 审查视觉布局和用户体验 5. 提交到App Store Connect

维护现有项目

对已有应用的持续开发:

You: Here's the next feature for Return: add a "Focus Score" that
     calculates from session duration and consistency. Show it on
     the main timer view. Build and test.

Claude: [reads CLAUDE.md, understands patterns]
        [reads TimerManager.swift, Settings.swift]
        [creates FocusScore.swift  model with calculation logic]
        [creates FocusScoreView.swift  display component]
        [integrates into ContentView.swift]
        [calls build_sim  1 error: missing import]
        [fixes import]
        [calls build_sim  success]
        [writes FocusScoreTests.swift]
        [calls test_sim  all pass]

Agent的效率与CLAUDE.md对项目当前状态的反映程度直接相关。当添加重要新功能、更改架构模式或引入新框架时,请及时更新CLAUDE.md。

何时借助Agent,何时不必

任务 使用Agent? 原因
新建SwiftUI视图 Agent擅长声明式UI
SwiftData模型变更 定义明确,可测试
单元测试 机械性工作,基于模式
重构 系统性,涉及多文件
构建错误诊断 是(通过 MCP) 结构化反馈循环
新建Xcode目标 需要Xcode UI和.pbxproj变更
签名与证书配置 基于开发者后台,Agent不可访问
视觉打磨 需要人工审美判断
Metal着色器调优 需要设备上的 GPU 测试
App Store提交 需要开发者后台和Xcode Organizer
性能分析 需要Instruments
无障碍审计 部分 Agent可添加标签,人工验证VoiceOver

配置 Agent 定义

如果使用Claude Code的 agent 定义系统(.claude/agents/),可以创建一个 iOS 专用 agent:

---
name: ios-developer
description: iOS development agent with MCP build tools and SwiftUI expertise
tools:
  - XcodeBuildMCP
  - xcode
---

# iOS Developer Agent

You are an iOS development agent for apps targeting iOS 26+ with SwiftUI.

## Architecture Rules
- @Observable for all view models (NEVER ObservableObject)
- NavigationStack for all navigation (NEVER NavigationView)
- SwiftData for persistence
- Swift 6.2 strict concurrency
- @MainActor on all Observable classes

## Build & Test — Always Use MCP

Prefer MCP tools over raw shell commands for ALL build operations:

- **Build**: `build_sim` / `build_device` (NOT `xcodebuild` via Bash)
- **Test**: `test_sim` / `test_device` (NOT `xcodebuild test` via Bash)
- **Simulators**: `list_sims`, `boot_sim`, `open_sim`
- **Debug**: `debug_attach_sim`, `debug_stack`, `debug_variables`
- **Apple docs**: `DocumentationSearch` (NOT WebSearch for Apple APIs)
- **Swift verification**: `ExecuteSnippet` (NOT `swift` via Bash)

MCP returns structured JSON. Bash returns unstructured text.

## File Management Rules
- NEVER modify .pbxproj, .xcodeproj/, .xcworkspace/, .xib, .storyboard
- Create Swift files in the correct directory
- Report files that need manual addition to Xcode targets

## SwiftData Rules
- @Model classes are automatically Observable — do not add @Observable
- Use @Bindable for form bindings to model properties
- Use @Query in views, modelContext.fetch() elsewhere
- Document relationship delete rules

## When You Get Stuck
- Build errors: use `build_sim` via MCP for structured output
- API questions: use `DocumentationSearch` via Apple MCP
- Swift verification: use `ExecuteSnippet` via Apple MCP
- Never guess — verify with tools

在Claude Code会话中通过 @ios-developer 引用此 agent。


Agent 辅助 iOS 开发的测试模式

Agent 在获得清晰指导后,能编写出优质的单元测试。以下是效果最佳的实践模式。

测试文件组织

# In CLAUDE.md:

## Test Structure

Tests mirror source structure:
- `ReturnTests/TimerManagerTests.swift` tests `TimerManager.swift`
- `ReturnTests/SettingsTests.swift` tests `Settings.swift`
- `ReturnTests/ConstantsTests.swift` tests `Constants.swift`

Test naming: `test_<what>_<condition>_<expected>`
Example: `test_start_whenStopped_transitionsToRunning`

测试提示词编写

高效的测试提示词:

Write unit tests for TimerManager covering:

1. Initial state is .stopped with timeRemaining == selectedDuration
2. start() transitions state to .running
3. pause() from .running transitions to .paused
4. reset() from any state returns to .stopped with original duration
5. start() from .paused resumes (state becomes .running)
6. Edge case: reset() when already stopped is a no-op
7. Edge case: pause() when already paused is a no-op

Follow the existing test pattern in SettingsTests.swift.
Use setUp() to create a fresh TimerManager for each test.

为什么有效: 编号验收标准为 agent 提供了清晰的核查清单。引用已有测试文件确立了编码范式。指定 setUp() 用法可防止 agent 创建纠缠不清的测试状态。

低效的测试提示词:

Write tests for TimerManager.

这种写法只会产出泛泛而谈的浅层测试,遗漏边界情况,也可能不符合项目的既有模式。

异步测试模式

针对计时器和异步代码的测试:

// Agent produces this pattern when guided correctly:
final class TimerManagerTests: XCTestCase {
    var sut: TimerManager!

    @MainActor
    override func setUp() {
        super.setUp()
        sut = TimerManager()
    }

    @MainActor
    func test_start_whenStopped_transitionsToRunning() {
        // Given
        XCTAssertEqual(sut.state, .stopped)

        // When
        sut.start()

        // Then
        XCTAssertEqual(sut.state, .running)
    }

    @MainActor
    func test_timerCountsDown_afterOneSecond() async throws {
        // Given
        sut.selectedDuration = 10
        sut.reset()
        sut.start()

        // When
        try await Task.sleep(for: .seconds(1.1))

        // Then
        XCTAssertLessThanOrEqual(sut.timeRemaining, 9.0)
    }
}

需要反复提醒 agent 的关键模式: - 测试 @MainActor 类时,测试方法也需要标注 @MainActor - 使用 Task.sleep 或异步操作的测试需声明 async throws - 时间相关断言要留有容差(用1.1秒而非精确的1.0秒) - 使用 setUp() / tearDown() 确保测试隔离

快照测试

如需检测视觉回归,建议引入 swift-snapshot-testing

Add snapshot tests for the main timer view in three states:
1. Stopped (showing full duration)
2. Running (showing countdown)
3. Completed (showing 00:00 with completion state)

Use SnapshotTesting library. Create reference images on first run.

Agent 能正确搭建快照测试,但无法审查参考图像。初始快照由您审核,之后 agent 的测试会自动捕获后续变更中的视觉回归。


iOS 项目的上下文窗口管理

1M上下文窗口(Opus 4.6)虽大但并非无限。iOS 项目有其特定的上下文管理注意事项。

iOS 文件的 Token 消耗

文件类型 典型大小 大致 Token 数
SwiftUI 视图(简单) 50-100行 500-1,000
SwiftUI 视图(复杂) 200-400行 2,000-4,000
SwiftData 模型 30-80行 300-800
Manager/Service 类 100-300行 1,000-3,000
Metal 着色器(.metal) 50-200行 500-2,000
单元测试文件 50-200行 500-2,000
CLAUDE.md 100-300行 1,000-3,000
MCP 响应(构建) 不定 200-2,000
MCP 响应(测试) 不定 500-5,000

50个文件的项目: 读取全部文件约消耗50,000-100,000个 token——完全在1M窗口范围内。Agent 可以将整个项目保持在上下文中。

100+文件的项目: 需要选择性读取。Agent 先读取 CLAUDE.md(获取文件结构标注),再按需读取特定文件。这就是 CLAUDE.md 中文件标注至关重要的原因——它引导 agent 直达目标文件,无需遍历所有内容。

大型项目的策略

  1. 详尽的 CLAUDE.md 文件标注 — Agent 读取文件地图后直接导航到相关文件
  2. 子 agent 委派 — 将探索和研究任务路由给子 agent(独立上下文,返回摘要)
  3. 聚焦式提示词 — “修改 SettingsView.swift 添加一个新开关”优于”更新设置”
  4. 合理的会话边界 — 不相关的功能开启新会话,而非延长当前会话
  5. 使用 /compact — Claude Code的压缩命令可总结对话并释放上下文

MCP 的 Token 效率

选择MCP的有力论据之一:结构化JSON响应消耗的 token 远少于原始 xcodebuild 输出。

场景 原始 Bash Token 数 MCP Token 数 节省比例
构建成功 3,000-10,000 200-500 85-95%
构建失败(1个错误) 3,000-10,000 300-800 90-92%
测试结果(20个测试) 2,000-5,000 500-1,000 75-80%
模拟器列表 500-2,000 200-400 60-80%

在典型的开发会话中,经过10-20次构建循环,MCP相比原始 xcodebuild 可节省30,000-150,000个 token——这些 token 得以保留给实际的代码推理。


故障排除

“build_sim failed — scheme not found”

Agent 在猜测 scheme 名称。解决方法:

Use discover_projs and list_schemes to find the correct scheme name
for this project before building.

或在 CLAUDE.md 中显式添加 scheme 名称:

## 构建配置
Primary scheme: `Return` (iOS)
Watch scheme: `ReturnWatch` (watchOS)
TV scheme: `ReturnTV` (tvOS)

“xcrun mcpbridge — command not found”

需要 Xcode 26.3 或更高版本。使用 xcodebuild -version 检查版本号。如果已安装 Xcode 26.3+ 但命令仍然失败:

# Ensure Xcode command line tools are selected
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer

# Verify
xcrun mcpbridge --help

“MCP 工具未在 Claude Code 中显示”

会话中途注册的 MCP 工具可能不会立即生效,需要重启才能加载。退出 Claude Code 并启动新会话:

# Exit current session (Ctrl+C or /exit)
# Start fresh
claude

然后验证:

You: List all available MCP tools from XcodeBuildMCP.

“Agent 一直通过 Bash 使用 xcodebuild,而非 MCP”

Agent 未通过 Tool Search 发现 MCP 工具。两种解决方案:

  1. 在 CLAUDE.md 中添加明确指引(参见教 Agent 使用 MCP
  2. 直接提示: “Use the build_sim MCP tool, not xcodebuild via Bash”

“构建成功但 Agent 报告失败”

XcodeBuildMCP 会解析 xcodebuild 的输出。如果构建产生了看似错误的警告(弃用警告中常见此情况),Agent 可能会误判结果。请检查 MCP 响应中的实际状态字段。

“模拟器启动时卡住”

关闭所有模拟器并重新启动:

xcrun simctl shutdown all
xcrun simctl boot "iPhone 16 Pro"

或直接让 Agent 处理:

Shut down all simulators, then boot a fresh iPhone 16 Pro.

“Agent 无视 CLAUDE.md 规则,试图修改 .pbxproj”

CLAUDE.md 中的规则只是建议,Hook 才是强制执行机制。如果没有配置 PreToolUse Hook 来阻止 .pbxproj 写入,Agent 终究会尝试修改它。安装以下 Hook:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "bash -c 'INPUT=$(cat); FP=$(echo \"$INPUT\" | jq -r \".tool_input.file_path // empty\"); if echo \"$FP\" | grep -qE \"\\.(pbxproj|xcworkspace|xib|storyboard)$|xcodeproj/|xcworkspace/\"; then echo \"BLOCKED: Do not modify Xcode project files.\" >&2; exit 2; fi'"
      }
    ]
  }
}

规则说的是”请不要”,Hook 说的是”你不能”。


常见问题

应该从哪个 Agent 运行时开始?

推荐 Claude Code CLI 搭配 XcodeBuildMCP。它拥有最深度的 MCP 集成、最成熟的 Hook 系统,以及能将整个 iOS 项目纳入工作记忆的 1M 上下文窗口(Opus 4.6)。从这里起步,待工作流成熟后再引入 Codex 做代码审查、Xcode 原生 Agent 做快速内联编辑。

两个 MCP 服务器都需要吗?

对大多数开发者而言,XcodeBuildMCP 已能覆盖 90% 的需求(构建、测试、模拟器、调试)。如需文档搜索、Swift REPL 验证或 SwiftUI 预览渲染,再添加 Apple 的 Xcode MCP。两个服务器相互独立,随时可以按需添加。

Agent 能从零创建新的 Xcode 项目吗?

XcodeBuildMCP 提供了 create_project 工具来搭建新的 Xcode 项目。但对于生产级应用,建议在 Xcode 中手动创建项目(以确保签名、功能权限和 Target 配置正确),然后将所有代码实现交给 Agent。在 Xcode 新建项目向导中花费的 5 分钟,能节省数小时因 Agent 生成的项目配置问题带来的排查时间。

Agent 如何处理 Swift Package Manager 依赖?

处理得很好。Package.swift 是标准 Swift 文件,Agent 能可靠地读取和编辑。添加依赖、更新版本范围、配置 Target 都不在话下。局限在于基于 .xcodeproj 的依赖管理(Xcode 的包解析 UI)——这部分由 Xcode 管理,不应由 Agent 编辑。

Agent 能提交到 App Store 吗?

不能。App Store 提交涉及 Xcode 的 Organizer、描述文件、截图、元数据以及 App Store Connect 门户。这些都无法通过 MCP 或命令行工具以 Agent 能有效操作的方式访问。Agent 负责归档之前的一切——实现、测试、修复和文档。提交的最后一步仍需人工完成。

不过,Agent 可以协助准备 App Store 元数据。可以让 Agent 根据最近的变更撰写应用描述、关键词和”新功能”文案。这属于文本生成工作,正是 Agent 的强项。

在 Agent 辅助的 iOS 开发中如何处理密钥和 API Key?

绝对不要提交密钥。对于需要连接后端 API 的 iOS 应用:

  1. 使用 .xcconfig 文件管理环境相关配置
  2. .xcconfig 文件加入 .gitignore
  3. 通过 Info.plist 构建设置引用配置值
  4. 在 CLAUDE.md 中记录所需密钥,但不包含实际值
## Configuration

API base URL and keys are in `Config.xcconfig` (not committed).
Required keys:
- `API_BASE_URL` — Backend server URL
- `API_KEY` — Authentication token

Create `Config.xcconfig` from `Config.xcconfig.template`.

Agent 知道密钥的存在及使用位置,但永远看不到实际值。

SwiftUI 动画方面——Agent 能编写吗?

Agent 在语法层面能正确编写动画代码,但无法从视觉上验证效果。简单动画(.animation(.spring()).transition(.slide)withAnimation { })通常能产生正确结果。复杂的多步动画若涉及精确时序控制,则需要 Agent 无法完成的视觉迭代调优。

有效提示: “Add a spring animation when the timer transitions between states.”

无效提示: “Make the timer animation feel satisfying.”(过于主观,需要视觉调优。)

Agent 如何处理错误处理模式?

表现出色。Agent 能熟练运用 Swift 的 do/catchResultasync throws 模式:

Implement error handling for the HealthKit authorization flow:
1. Check HKHealthStore.isHealthDataAvailable()  show alert if not
2. Request authorization  handle denial gracefully
3. On write failure  retry once, then show error
4. All errors should be user-facing with localized descriptions

Agent 能生成结构化的错误处理代码,并附带恰当的用户提示信息。它们有时会过度处理错误(捕获了本应向上传播的异常),因此需要审查 catch 块。

能用 Agent 实现无障碍功能吗?

部分可以。Agent 能正确添加无障碍标签、提示和特征:

Add accessibility labels to all interactive elements in TimerView:
- Timer display: current time remaining
- Start/Pause button: current state and action
- Reset button: "Reset timer"
- Duration picker: selected duration

Agent 无法做到的是:验证 VoiceOver 导航顺序是否正确、测试动态字体缩放效果,或评估颜色对比度。这些需要使用 Xcode 的 Accessibility Inspector 进行验证。

Agent 如何处理 Core Data 迁移(未使用 SwiftData 的情况)?

Agent 能编写 Core Data 迁移映射和模型版本,但手动 Xcode 操作步骤(创建新模型版本、选择当前版本)无法自动化。如果仍在使用 Core Data 而非 SwiftData,请在 CLAUDE.md 中记录模型版本历史:

## Core Data 模型版本
- V1:初始版本(GroceryList、GroceryItem)
- V2:新增 Category 模型(当前版本)
- 迁移:V1→V2 采用轻量级自动迁移

AI 代理如何处理 SwiftUI 预览?

有两种方式: 1. Apple Xcode MCP 的 RenderPreview 工具可在无界面环境下渲染预览并返回结果。代理能验证预览是否编译成功且无错误,但无法评估视觉效果的正确性。 2. 基于构建的验证通过 build_sim 确认预览提供器能够编译。如果预览在运行时崩溃,构建仍会成功——崩溃只会在 Xcode 尝试渲染预览时才会显现。

若需对预览进行视觉验证,仍需打开 Xcode。

visionOS 和 Apple Vision Pro 呢?

同样的模式完全适用。XcodeBuildMCP 支持 visionOS 模拟器,架构模式(@Observable、NavigationStack、SwiftData)也完全一致。RealityKit 相关代码(3D 内容、沉浸式空间、手势追踪)与 Metal 面临相同的局限——代理能编写正确的代码,但无法验证空间输出效果。

项目规模多大时代理会力不从心?

上下文窗口大小是关键制约因素。凭借 Opus 4.6 的 1M token 窗口,Claude Code 可以同时在活动工作记忆中容纳约 50-70 个 Swift 文件。对于更大的项目,代理会通过文件搜索和选择性读取来处理代码库的子集。100+ 文件的项目完全没有问题——代理只是按需读取文件,而非将所有内容保持在上下文中。

实际上,限制因素并非文件数量,而是代码库的规范程度。一个文档完善、拥有详尽 CLAUDE.md 的 200 文件项目,效果远优于一个缺乏文档的 30 文件项目。

使用代理进行 iOS 开发需要懂 Swift 吗?

你需要具备审查代理输出和做出架构决策的能力。不必亲手编写每一行代码,但要对 Swift 有足够的理解,才能在代理做出错误选择时及时发现——尤其是在并发、内存管理和框架特定模式方面。代理是你现有技能的 10 倍放大器,而非替代品。

代理如何处理 Swift 文件中的合并冲突?

代理能可靠地解决 Swift 源文件中的合并冲突。所有代理运行时都能正确理解标准冲突标记(<<<<<<<=======>>>>>>>)。然而,.pbxproj 文件中的合并冲突仍需手动解决——不要让代理处理 .pbxproj 冲突。

使用代理进行 iOS 开发的成本如何?

使用 Anthropic 的 Max 计划(Opus 4.6,1M 上下文),典型的 iOS 开发会话持续 30-120 分钟,处理 200K-800K token。MCP 工具调用的额外开销极小(结构化的 JSON 响应相比原始构建输出更节省 token)。成本与在任何其他代码库上运行 Claude Code 相当——iOS 开发在费用上与 Web 开发并无显著差异。

代理能用于 UIKit 项目吗?

可以,但代理在 SwiftUI 项目中表现更为出色。UIKit 需要更多样板代码,声明式结构较少,且经常涉及代理无法编辑的 Interface Builder 文件。如果你有 UIKit 项目,建议让代理负责模型层和业务逻辑,UI 部分手动处理,或者逐步将视图迁移到 SwiftUI。

代理如何处理本地化?

代理能有效地创建和编辑 .xcstrings(Xcode 字符串目录)文件。它们可以添加新的本地化键、提供翻译,并保持跨语言的一致性。.xcstrings 文件的结构化 JSON 格式对代理非常友好。对于 .strings 文件(旧格式),代理同样表现良好——键值对格式简单直观。


iOS 开发中常见的代理错误(及预防方法)

以下是我在 8 个 iOS 项目、数千次代理交互中反复观察到的错误,每个错误都附有相应的预防策略。

错误 1:混用 Observable 模式

表现:代理在一个文件中使用 @Observable,在另一个文件中使用 ObservableObject,或者给 @Model 类添加 @Observable(该类本身已具备 Observable 特性)。

预防:在 CLAUDE.md 中明确规则:

- NEVER use ObservableObject — use @Observable
- NEVER add @Observable to @Model classes (already Observable)
- NEVER use @StateObject — use @State with @Observable
- NEVER use @ObservedObject — access @Observable properties directly

错误 2:在闭包中创建循环引用

表现:代理创建的闭包强引用了 self,尤其在 Timer.publishNotificationCenter 和完成处理器中。

预防:在 CLAUDE.md 中加入闭包模式:

## Closure Pattern
- Timer callbacks: use `[weak self]` and guard
- NotificationCenter observers: store in `Set<AnyCancellable>` and use `[weak self]`
- Completion handlers: use `[weak self]` for any closure stored beyond the call site

错误 3:忽略 @MainActor 要求

表现:代理创建 @Observable 类时未添加 @MainActor 隔离,导致 Swift 6.2 并发警告或在非主线程更新 UI 时发生运行时崩溃。

预防:

## Concurrency Rule
ALL @Observable classes MUST be @MainActor:
```swift
@Observable
@MainActor
final class SomeManager { }
### 错误 4:使用带目标闭包的 NavigationLink

**表现:**代理使用已弃用的 `NavigationLink(destination:label:)` 而非类型安全的 `NavigationLink(value:)` + `.navigationDestination(for:)` 模式。

**预防:**
```markdown

## Navigation Pattern
ALWAYS use value-based navigation:
```swift
NavigationLink(value: item) { ItemRow(item: item) }
.navigationDestination(for: Item.self) { ItemDetailView(item: $0) }

NEVER use: NavigationLink(destination: ItemDetailView(item: item)) { }

### 错误 5:硬编码模拟器名称

**表现:**代理在构建命令中写入特定的模拟器名称(如 "iPhone 16 Pro"),而该模拟器可能在你的系统上并不存在。

**预防:**MCP 已处理此问题——`list_sims` 可发现可用的模拟器。在 CLAUDE.md 中:
```markdown

## Simulators
Do NOT hardcode simulator names. Use `list_sims` MCP tool to discover
available devices, then `boot_sim` with the discovered device ID.

错误 6:在错误目录中创建文件

表现:代理将新的视图文件创建在项目根目录而非 Views/ 子目录中,或将模型放在了错误的分组下。

预防:CLAUDE.md 中的文件结构注解可引导正确放置。此外:

## File Placement Rules
- Views → `AppName/Views/`
- Models → `AppName/Models/`
- Managers → `AppName/Managers/`
- Extensions → `AppName/Extensions/`
- Tests → `AppNameTests/`

错误 7:未处理平台可用性

表现:代理在共享代码中使用了 HealthKit,而该代码会在 tvOS(HealthKit 不可用)上编译,或在 watchOS 代码中使用了 ActivityKit。

预防:

## Platform Guards
- HealthKit: `#if canImport(HealthKit)` (unavailable on tvOS)
- ActivityKit: `#if canImport(ActivityKit)` (iOS only)
- WatchKit: `#if os(watchOS)`
- UIKit haptics: `#if os(iOS)` (unavailable on tvOS, watchOS uses WKHaptic)

错误 8:过度工程化简单功能

表现:代理为一个本应 20 行就能解决的工具函数,创建了协议、协议扩展、具体实现、工厂和依赖注入容器。

预防:加入简洁性原则:

## Architecture Principle
Prefer the simplest solution that handles the requirements.
- Direct implementation over protocol abstraction (unless you have 2+ conforming types)
- Concrete types over generics (unless reuse is proven)
- Extensions on existing types over new wrapper types

坦诚的评价

在使用 AI 代理交付 8 个 iOS 应用之后,以下是我的总结:

代理所变革的:实现速度。过去需要数天的工作,现在几小时即可完成。SwiftUI 视图、SwiftData 模型、单元测试、重构——这些现在主要由代理生成、人工审查。

代理未能变革的:架构决策、视觉设计、性能优化以及 App Store 提交。这些仍然由人来主导。

效率倍增是真实的,但有上限。对于文档完善、配置了 MCP 和 hook 的项目,我估计生产力提升约 3-5 倍。而缺乏文档和 hook 的项目大约只有 1.5-2 倍的提升——代理把太多时间花在猜测而非构建上。

最值得的投入:花在 CLAUDE.md、hook 和 MCP 配置上的时间。每一小时的前期准备,都能节省大量纠正代理错误的时间。配置即产品——代理只是执行引擎。

最出乎意料的:MCP 服务器对开发模式的深远改变。在有 MCP 之前,代理不过是恰好懂 Swift 的高级文本编辑器。有了 MCP 之后,它们成为了能编写、构建、测试、调试和迭代的开发伙伴。结构化的反馈循环是”能写代码的代理”与”能交付代码的代理”之间的本质区别。

如果能对过去的自己说一句话:从最小的应用开始(Reps,14 个文件),先把 MCP 和 hook 配置调试到位,编写详尽的 CLAUDE.md,然后再将这套模式推广到更大的项目。不要一上来就挑战那个 63 文件的多平台应用。无论项目大小,基础设施的投入量是一样的——在小项目上一次做好,然后复制到其他所有项目。

展望未来:Xcode 26.3 原生代理集成是一个起点,而非终点。Apple 发布 MCP 支持意味着工具链正在向代理优先的开发模式迈进。那些现在就投入构建代理友好型项目结构的开发者——整洁的 CLAUDE.md 文件、可测试的架构、自动化的 hook——将随着工具的进步持续获得复利回报。


快速参考卡片

安装(一次性设置)

# XcodeBuildMCP (59 tools)
claude mcp add XcodeBuildMCP -s user \
  -e XCODEBUILDMCP_SENTRY_DISABLED=true \
  -- npx -y xcodebuildmcp@latest mcp

# Apple Xcode MCP (20 tools)
claude mcp add --transport stdio xcode -s user -- xcrun mcpbridge

# Codex MCP setup
codex mcp add xcode -- xcrun mcpbridge

# Verify
claude mcp list

CLAUDE.md 核心章节

1. Project identity (bundle ID, target OS, architecture)
2. File structure with annotations
3. Build and test commands
4. Key patterns and rules
5. Prohibitions (NEVER touch .pbxproj)
6. Framework-specific context

核心 Hook 配置

{
  "PreToolUse": [{ "matcher": "Edit|Write", "command": "block .pbxproj" }],
  "PostToolUse": [{ "matcher": "Edit|Write", "command": "swiftformat" }]
}

架构规则

@Observable         (not ObservableObject)
NavigationStack     (not NavigationView)
@State              (not @StateObject)
SwiftData @Model    (not Core Data)
async/await         (not completion handlers)
@MainActor          (on all Observable classes)
.glassEffect()      (Liquid Glass, iOS 26+)

MCP 工具优先级

Build:     build_sim          (not xcodebuild via Bash)
Test:      test_sim           (not xcodebuild test via Bash)
Sim:       list_sims/boot_sim (not xcrun simctl via Bash)
Docs:      DocumentationSearch (not WebSearch)
REPL:      ExecuteSnippet     (not swift via Bash)

更新日志

日期 变更内容
2026-04-13 首次发布。涵盖8款应用、3个运行时、MCP配置、CLAUDE.md模式、Hook机制及案例研究。

参考文献


  1. XcodeBuildMCP默认包含Sentry遥测功能。项目的隐私文档详细说明了所发送的数据:错误消息、堆栈跟踪,以及某些情况下的文件路径。设置XCODEBUILDMCP_SENTRY_DISABLED=true环境变量可完全禁用遥测。 

  2. Anthropic,”Model Context Protocol Specification,”modelcontextprotocol.io/specification。MCP规范定义了JSON-RPC传输协议、工具发现机制和资源协议,XcodeBuildMCP与Apple Xcode MCP均实现了该规范。 

  3. XcodeBuildMCP,github.com/getsentry/XcodeBuildMCP。由Sentry维护的开源项目,提供59个工具,覆盖模拟器、真机、调试和UI自动化工作流。采用语义化版本控制并附带变更日志。 

  4. Apple在Xcode 26.3智能开发者工具计划中引入了Xcode MCP服务器,将MCP定位为AI编程助手与Xcode工具链之间的接口层。详见Xcode Release Notes官方文档。 

  5. Rudrank Riyam,”Exploring Xcode Using MCP Tools,”rudrank.com/exploring-xcode-using-mcp-tools-cursor-external-clients,2026年。独立验证了Apple MCP的工具数量、XPC依赖关系及文档搜索功能。 

  6. Jimenez, C.E., Yang, J., Wettig, A.等,”SWE-bench: Can Language Models Resolve Real-World GitHub Issues?” ICLR 2024。arxiv.org/abs/2310.06770。研究表明,使用结构化工具访问的智能体显著优于仅依赖非结构化Shell命令的智能体,验证了结构化MCP接口对提升智能体效能的价值。 

  7. Claude Code CLI文档,code.claude.com。涵盖Hook系统、MCP配置、子代理委派及代理定义。 

  8. SwiftFormat,github.com/nicklockwood/SwiftFormat。PostToolUse Hook中使用的Swift代码格式化工具,确保代码风格一致。 

  9. XcodeBuildMCP官方网站,xcodebuildmcp.com。通过CLI输出示例确认提供59个MCP工具。工具类别涵盖:模拟器、真机、调试及UI自动化。支持通过Homebrew或npx安装。 

  10. Swiftjective-C,”Agentic Coding in Xcode 26.3 with Claude Code and Codex,”swiftjectivec.com,2026年2月。确认Xcode 26.3原生集成了Claude Agent和Codex运行时支持,可通过”设置 > 智能功能”开启,并通过xcrun mcpbridge暴露20个MCP工具。 

  11. Blake Crosley,”Two MCP Servers Made Claude Code an iOS Build System,”blakecrosley.com/blog/xcode-mcp-claude-code,2026年2月。来自同一作者的iOS开发工作流配置指南及实际使用成果。 

NORMAL ios-agent-development.md EOF