我现在用 Codex 写 iOS App,跟以前最大的区别,不是它更会写 SwiftUI 了。
SwiftUI 代码,AI 早就能写。
真正改变体验的是:我不再需要把 App 的运行现场手动搬给 AI。
以前我的流程大概是这样:
让 AI 改代码回到 Xcode 构建打开模拟器看一眼发现按钮歪了或者页面崩了截图复制报错再发回聊天窗口等 AI 根据二手信息继续猜
这个流程的问题不是慢一点,而是上下文一直在丢。
AI 不知道这张截图对应哪次构建,不知道错误日志前后发生了什么,也不知道我刚刚点过哪些按钮。它只能根据我转述的信息继续推。
所以我现在的做法是:尽量让 Codex 自己进入 iOS 开发现场。
让它读项目、改代码、构建、运行、看模拟器、抓日志。能在 Codex 里完成的反馈,就不要再靠我截图转述。
所以我不想把它写成工具清单。
更有价值的是,把我现在实际用 Codex 开发 App 的流程拆开。
我没有一上来装一堆 skill。
iOS 这条线,我先把最基础的环境跑通:
| |
|---|
| |
Build iOS Apps | |
| 让 Codex 读取原型、组件、颜色、字体和交互状态 |
| |
| 跑 XcodeBuildMCP、serve-sim 这类工具 |
这里最关键的是 Build iOS Apps 插件。
它里面已经带了我日常最常用的一组能力:
- •
ios-debugger-agent:让 Codex 构建、运行、调试模拟器里的 App。 - •
ios-simulator-browser:把模拟器画面放到 Codex 应用内浏览器里,也能跑 SwiftUI 预览。 - •
swiftui-ui-patterns:写 SwiftUI 页面、导航、sheet、表单、列表这些东西。 - •
swiftui-view-refactor:把巨大的 SwiftUI View 拆开。 - •
swiftui-performance-audit:看 SwiftUI 性能问题。 - •
ios-memgraph-leaks:抓 memgraph 排查泄漏。 - •
ios-ettrace-performance:做性能 trace。 - •
ios-app-intents:做 Shortcuts、Siri、Spotlight 这些系统入口。
我后来发现,最开始真不用装太多。
工具装得越多,Codex 可选路径越多,反而容易把一个小需求绕复杂。
我的原则是:设计侧先用 Figma 把原型定住,开发侧先用 Build iOS Apps 跑通主流程,遇到明确问题再补专项工具。
第一步,我不会让 Codex 直接写代码
我以前经常犯一个错误:
脑子里有个 App 想法,就直接让 AI“帮我实现一个 XXX”。
结果它很快会给我写出一堆页面、model、service、mock data,看起来很勤快,但过两天就开始乱。因为一开始没有说清楚:这个 App 到底先做什么,不做什么。
所以我现在第一步通常是让 Codex 帮我压需求。
我会这样问:
请以 Build iOS Apps 作为 iOS 工作流基线。我想为 <目标用户> 做一个 iOS app,用来解决 <问题>。请把它整理成 v0.1 PRD:- 核心用户任务- 首版页面- 数据模型- App Intents 机会- 第一周 MVP- 明确不做什么
这里最重要的是最后一项:明确不做什么。
AI 写代码太快了,快到我很容易误以为“多做一点也没关系”。但 iOS App 最怕的不是少一个功能,而是首版边界不清楚。
我宁愿先让 Codex 把 v0.1 缩小,也不想一开始就得到一个看起来很完整、实际没人维护得动的项目。
第二步,我会先做 Figma 原型
需求定下来以后,我不会马上让 Codex 写 SwiftUI。
我会先做一版 Figma 原型。
原因很简单:设计阶段不只是把页面画漂亮,而是把信息架构、页面层级和交互路径先定下来。
如果跳过这一步,Codex 很容易直接把 PRD 翻译成一堆 SwiftUI 页面。页面看起来都在,但导航关系、主次信息、空状态、按钮层级和异常状态经常是它自己猜的。
我现在更希望 Codex 实现的是一份已经确认过的原型,而不是让它边写代码边替我做产品设计。
我的 Figma 原型一般不会一开始追求特别精细,但至少要把这些东西定清楚:
- • 表单输入、按钮禁用、确认弹窗这些交互状态怎么处理
如果已经有 Figma 文件,我会让 Codex 先读设计,不急着实现:
请使用 Figma 检查这个 frame:<figma-url-with-node-id>。提取页面结构、组件清单、字体、颜色、资源和交互状态。先不要实现,请先产出 SwiftUI 实现计划。
如果原型还没做完,我会让 Codex 先帮我反查一遍:
请根据这份 v0.1 PRD,检查当前 Figma 原型是否覆盖了核心用户路径。重点看:页面是否缺失、状态是否缺失、导航是否闭环、哪些交互在开发时会产生歧义。先输出问题清单,不要写代码。
这一步对我很重要。
我不想把“设计没想清楚”的成本拖到 SwiftUI 代码里解决。代码一旦写出来,哪怕只是半成品,也会让人下意识沿着已有结构继续补。
原型阶段把结构推翻,成本很低。
写进工程以后再推翻,成本就高很多。
第三步,我先搭 App 壳
需求压住、原型过了一遍以后,我不会马上做某个具体页面。
我会先搭 App 壳。
也就是这些东西:
- • 每个 Tab 里面有没有自己的
NavigationStack
这一步我通常会直接点名 swiftui-ui-patterns:
请使用 Build iOS Apps 的 `swiftui-ui-patterns` 创建 app 壳:- TabView 包含 Home、Search、Settings- 每个 tab 拥有自己的 NavigationStack- 使用 enum-based route model- 使用 enum-based sheet model- 添加最小可用 previews修改后请 build,并修复编译错误。
我比较在意这里的两个词:enum-based 和 previews。
路由和 sheet 如果早期就随手写,后面页面一多会很烦。用 enum 管起来,Codex 后面继续加页面时也更容易沿着同一套结构走。
preview 也一样。
我现在会尽量要求 Codex 在写页面时顺手补最小可用 preview。不是为了形式完整,而是为了后面能更快地看组件状态。
第四步,页面一页一页做
App 壳稳定以后,我才开始让 Codex 做具体页面。
我不会说“把所有页面都实现一下”。
这种提示词很容易得到一堆半成品。
我现在更喜欢一次只做一个用户任务,比如“新建一条笔记”“保存一个体重记录”“完成一次 onboarding”。
例如做一个笔记编辑页,我会这样写:
请使用 Build iOS Apps 的 `swiftui-ui-patterns` 实现 NoteEditor 页面。需要:- 标题输入- Markdown 正文编辑器- 保存状态- 未保存变更确认- accessibility labels遵循现有项目模式。实现后请 build,并修复编译错误。
这里有个细节:我会明确要求它“遵循现有项目模式”。
因为 Codex 很容易在不同文件里引入不同风格。有的地方用 service,有的地方用 view model,有的地方又直接在 view 里写逻辑。
所以我现在会反复强调:先看现有结构,再动手。
如果发现某个 SwiftUI View 已经太大,我不会继续往里面塞功能,而是先让它拆:
请使用 Build iOS Apps 的 `swiftui-view-refactor` 把 ContentView.swift 拆成小而明确的子视图。业务逻辑保留在 services/models 中,view 自己拥有的状态留在本地。除非现有项目已经使用 MVVM,否则不要引入 MVVM。
最后这句也很重要。
我不想让 Codex 为了“看起来专业”,突然给一个小项目套上完整 MVVM。SwiftUI 里很多页面先用更直接的状态和组合方式,反而更清楚。
第五步,每做完一段就让它跑起来
这是我现在流程里变化最大的一点。
以前我让 AI 写完代码,自己去 Xcode 里跑。
现在我会直接让 Codex 构建和运行:
请使用 Build iOS Apps 的 `ios-debugger-agent`。发现当前 iOS project/workspace 和 schemes,给已启动的模拟器设置 session defaults,构建并运行 app,描述当前可见 UI,并抓取相关日志。
这一步能省掉很多来回解释。
如果构建失败,Codex 能看到编译错误。
如果运行后首屏不对,它能描述当前 UI。
如果控制台有异常,它能把日志拿回来继续分析。
我现在不太接受“代码已经实现”这种结束语。对 iOS App 来说,至少要 build 过,最好能跑到对应页面。
所以我常用的要求是:
重新 build and run。然后依次点击 Home -> New Note -> Save。如果 UI、日志或状态有问题,请先报告,再修复。
这句话的重点是让 Codex 按用户路径走,而不是只编译通过。
App 开发里很多问题不是编译错误,而是路径错误:按钮状态不对、保存后没跳转、sheet 没关、空状态没刷新。
这些都需要跑起来看。
第六步,把模拟器画面放进 Codex
Build iOS Apps 里我最喜欢的能力,是 ios-simulator-browser。
它可以把模拟器画面放进 Codex 的应用内浏览器。
我会这样用:
请使用 Build iOS Apps 的 `ios-simulator-browser`,把已启动的模拟器镜像到 Codex in-app browser,并视觉验证 onboarding 流程。
底层大致会用到:
npx --yes serve-sim@latest "<simulator-udid-or-device-name>"
这件事的价值不是“我少打开一个窗口”。
真正的价值是:Codex 可以围绕同一个画面继续工作。
比如我让它检查 onboarding,它看到的不是我口头描述的“第二页有点挤”,而是当前模拟器里的真实画面。它可以结合代码、日志和画面一起判断。
这个时候,Codex 才真的像在和我一起调 App,而不是在远程听我复述。
第七步,SwiftUI 预览能拆就拆出来
如果是组件级迭代,我会尽量用 SwiftUI Preview。
ios-simulator-browser 对 Swift Package 里的 PreviewProvider 和 #Preview 有一条专门工作流:它会生成一个临时 host project,在模拟器里跑 preview,并监听源码变化。
命令大致是:
node <skill-root>/scripts/swiftui-preview-browser.mjs \ /absolute/path/to/Package.swift \ --package-target "<target>" \ --device "<simulator-udid>"
我喜欢这条路线的原因是,它不会为了跑 preview 去改我的 .xcodeproj、.xcworkspace、Package.swift 或 scheme。
它是在源码树外面生成临时宿主。
这对长期项目很重要。
我不希望为了让 AI 看一眼预览,把工程配置弄脏。
当然,这也意味着我会更倾向于把可复用组件放到更清晰的 Swift Package 或模块边界里。这样 Codex 后面做 preview、热重载和视觉检查都更顺。
第八步,专项工具只在需要时加
除了前面已经用到的 Figma,我不会一开始就把 SwiftData、Swift Testing、App Store 这些工具全接上。
我现在是按问题加。
如果项目真的用了 SwiftData,我再加 SwiftData 专项 skill:
npx skills add https://github.com/twostraws/swiftdata-agent-skill --skill swiftdata-pro
然后让它专门看模型、关系、迁移和 iCloud sync:
$swiftdata-pro 请设计 Notes、Tags、Attachments 的 SwiftData 模型。包含 @Model 定义、关系、索引、迁移风险和 iCloud sync 注意事项。
如果开始认真补测试,我再加 Swift Testing:
npx skills add https://github.com/twostraws/swift-testing-agent-skill --skill swift-testing-pro
提示词也尽量具体:
$swift-testing-pro 请为 NoteParser 添加 Swift Testing 覆盖。适当使用参数化测试、#expect、#require 和 async tests。
我的经验是:工具越专项,越应该在问题明确以后再用。
不然很容易变成“为了用工具而设计流程”。
第九步,卡顿和泄漏不要靠猜
性能问题我也不想让 Codex 纯靠读代码猜。
如果是 SwiftUI 卡顿,我会先让它做代码层面的审查:
请使用 Build iOS Apps 的 `swiftui-performance-audit` 审查 FeedView.swift 的滚动卡顿问题。重点检查 identity 不稳定、observation 范围过大、body 中的重计算、图片解码和 layout thrash。
如果是启动慢或某个流程卡,我再让它抓 trace:
请使用 Build iOS Apps 的 `ios-ettrace-performance` 分析模拟器上的 app 启动性能。抓取一个聚焦的 launch trace,保留 artifacts,分析处理后的 flamegraph JSON,并报告热点。
如果怀疑泄漏,就抓 memgraph:
请使用 Build iOS Apps 的 `ios-memgraph-leaks`。复现流程:打开 editor,添加 note,保存,关闭 editor。抓取 memgraph,并识别 app 自有代码里的泄漏类型和 ownership paths。
这类问题最怕一句“可能是状态刷新太多”。
可能没用。
我现在更愿意给 Codex 一个明确复现路径,再让它围绕 trace、日志和 memgraph 说话。
第十步,上架前再接发布工具
到 TestFlight 和 App Store 阶段,我会接 asc。
安装很简单:
brew install asc
常用命令大概是这些:
asc apps list --output tableasc builds upload --app "123456789" --ipa "/path/to/MyApp.ipa"asc status --app "123456789" --watch
但我不会把发布完全交给 Codex。
我的用法更像让它做检查清单:
请使用 asc-release-flow 检查我的 app 1.2.3 版本是否已经可以提交 App Store。请区分 API 可修复阻塞、需要浏览器 session 的阻塞,以及必须手动处理的阻塞。
首次提交前,我还会单独做 App Review 检查:
$app-store-review 请审查这个 iOS app 的 App Store 合规性。重点检查隐私、IAP、账号删除、权限、后台模式、用户生成内容和元数据准确性。请返回带文件引用的阻塞问题。
发布这件事,我不会追求全自动。
账号、证书、隐私、审核策略、元数据,这些还是要人自己把关。Codex 适合帮我发现遗漏、整理命令、区分哪些能 API 修,哪些必须手动处理。
我现在的完整节奏
如果把上面的流程压成一张清单,我现在大概是这样用 Codex 做 iOS App:
1. 先让 Codex 写 v0.1 PRD,尤其要写清楚不做什么2. 先用 Figma 做原型,把页面结构和核心交互定下来3. 让 Codex 读取 Figma,先产出 SwiftUI 实现计划4. 用 Build iOS Apps 作为默认 iOS 工作流5. 先搭 SwiftUI App 壳,不急着铺所有页面6. 一次只做一个用户任务7. 每做完一段就 build and run8. 能看模拟器画面,就让 Codex 自己看9. 组件能拆 preview,就优先走 SwiftUI Preview10. 数据、测试、并发、发布这些专项工具按需再加11. 性能和泄漏用 trace / memgraph 说话12. 上架前让 Codex 做检查,但最终判断自己负责
这套流程的核心不是“Codex 能写多少代码”。
而是我把原来分散在几个地方的反馈,尽量都接回 Codex:
当这些东西都在一个上下文里,Codex 才能真正持续参与开发。
最后的感受
我现在越来越少把 Codex 当成“帮我写代码的聊天窗口”。
它更像一个可以进入项目现场的开发搭子。
我给它的不是一句“帮我做个 App”,而是一条具体路径:
先定范围再做原型再搭结构一页一页做做完就跑跑完就看看完再改
这才是我觉得 Codex 开发 iOS App 真正变顺的地方。
不是 AI 一次性把 App 生成出来。
而是我终于不用在 Xcode、模拟器、截图和聊天窗口之间来回搬运上下文了。