过去一段时间,社区里频繁出现用 AI 快速逆向商业产品或像素级复刻热门应用的案例。只要 Token 充足,搭建一个免费的“影子版本”似乎已不再是难事。
与此同时,许多坚持“公开构建”(Build in Public)的独立开发者也遭遇了新的挑战:原创产品尚在打磨之中,一些仿制者仅凭作者在社交媒体上披露的设计截图和思路,便借助 AI 抢先一步上线了“克隆品”。有的源于技术探索与好奇,有的只是想展示 AI 工具的生产力,但也不乏投机取巧的捷径心态。
看着这股风气,我始终感到一丝不安。
复刻与模仿在过去几十年中一直都存在,但 AI 大幅压缩了实现所需要的时间与成本。原创者可能花费数月才找到一个值得做的方向,模仿者却可以观察最终结果,跳过大量试错,在极短时间内做出一个外观和功能都颇为相似的版本。
商业竞争当然需要鲶鱼,AI 对原创者同样有所帮助。如果更低的实现门槛能够促使原创团队加快创新、改善体验,或者提供更具性价比的服务,自然是消费者乐于看到的结果。更何况,复制界面与功能并不等于复制产品本身,那些隐藏在细节中的设计判断和对用户需求的理解,并不是一次像素级复刻就能获得的。
但并不是每个原创者都有足够的时间和资源,等待市场认识到这些差异。对于成熟的商业产品,几个 AI 仿制品或许不足以构成真正的威胁;但对于仍在寻找市场位置的独立开发者,几周甚至几个月的时间差就可能非常重要。
曾经,通过 Build in Public 分享创意、设计与开发过程,是独立开发者建立社区、获得反馈的一种方式。更重要的是,它让大家愿意在产品还不成熟的时候,就拿出自己的想法、尝试甚至失败,与其他开发者交流。
这种氛围并不是天然存在的,而是这些年一点点形成的。
但当公开的信息同时成为别人寻找复刻目标、快速跳过探索阶段的捷径,分享所需要承担的风险也发生了变化。如果越来越多的开发者发现,在产品真正准备好之前,保持沉默比公开分享更加安全,那么 Build in Public 或许真的会重新变成 Build in Private。
这才是最让我不安的地方。
我们失去的可能不只是几个尚未问世的原创产品,而是独立开发者好不容易形成的、愿意彼此展示不成熟想法并相互启发的交流氛围。
原创
AI-Friendly Framework:当抽象上移,验证如何跟上?
随着 AI Coding 的普及,不少人开始倾向一种观点:UIKit 这样的命令式框架,可能比 SwiftUI 更适合 Coding Agent。理由很直观——UIKit 的逻辑直接明确:创建对象、设置属性、加入层级、建立约束,每一步都有具体操作的实体;而 SwiftUI 把大量实现细节收束在声明式语法之后,状态、环境、身份、布局与渲染共同决定了最终结果。一旦呈现效果偏离预期,Agent 只能对着黑盒,从有限的外部现象去反推内部究竟发生了什么。
但问题或许并不在抽象本身,而在于抽象之后我们漏掉了另一半工作:观察与验证。当抽象隐藏了底层细节,我们必须在新的层级上,补齐能够固定并验证意图的手段。
近期推荐
重审「局部隔离」的利弊与权衡 (Revisiting “Split Isolation”)
在一个本身没有 actor isolation、且 non-Sendable 的类型中,只给部分方法添加 @MainActor,会让同一个实例同时具有不同的隔离要求。Matt Massicotte 将这种模式称为 “split isolation”。包括 Matt 自己在内,不少开发者都认为这并非一个好的设计。
在本文中,Matt 重新审视了自己过去的判断:split isolation 虽然仍应尽量避免,但在特定场景仍有存在价值。尤其在只有少量独立功能依赖 MainActor,或者正在向 Swift 6 迁移、不希望隔离要求迅速扩散到大量既有代码时,局部添加 @MainActor 也可能是一种合理甚至必要的权衡。是否采用 split isolation,关键在于它是在掩盖类型真正的隔离需求,还是在有意识地表达一个局部约束。
超越 async/await:Task 不是业务工作的基本单元 (The Task Is Not the Unit of Work: Ownership, Isolation, and Cancellation Beyond async/await)
SwiftUI 的 .task 会随着视图消失自动取消任务,这很方便,但也很容易让开发者顺手将各类业务操作的生命周期绑定到 UI 的生命周期。不过,页面消失并不意味着用户的意图已经失效。
Bruno Valente Pimentel 指出:Task 是执行单元,却不一定是产品工作的单元;Actor 解决 isolation,却不会决定谁应该拥有这项工作;结构化并发能够传播 cancellation,却无法判断这种父子关系是否符合产品语义。相比先考虑“Task 应该放在哪里”,Bruno 建议首先明确操作的 intent、owner、resource 和 lifetime,然后再选择具体的实现机制。编译器可以帮助我们保证并发安全,但无法替我们决定一项工作什么时候才真正“不再重要”。
SwiftUI 日历组件的边界与状态设计 (A SwiftUI calendar with custom days and event indicators)
实现一个日历 UI,真正麻烦的往往不是画出日期网格,而是处理背后的状态与边界条件:如何将当前显示日期与选择范围分离;统一通过 Calendar 处理日期运算和 day boundary;正确应对 first weekday、跨月份、夏令时以及非 Gregorian Calendar;点击与拖动如何共同完成连续的范围选择;避免每个 cell 重复扫描事件列表;避免不必要的 cell 视图重建等挑战。Szymon Lorenz 分享了他为 SwiftUIComponents 开发日历组件的经验,这个开源项目通过 Skip Fuse 还提供了 Android 端的兼容性。
100,000 个事件下的 SwiftUI 性能排查实战 (SwiftUI Profiling with Instruments: 100,000 Calendar Events)
当一个包含大量数据的 SwiftUI 应用出现卡顿时,问题究竟来自数据库、数据处理,还是视图更新?Maciej Szamowski 使用包含 100,000 个事件的测试数据库对 hora Calendar 进行压力测试,通过 Instruments 的 SwiftUI、Hangs、Hitches 和 Time Profiler,发现卡顿期间大量主线程时间消耗在 SwiftUI graph updates 上,从而将优化重点从数据库转向了数据准备和视图更新路径。
前后两篇有关日历的文章在改善渲染性能上都采用了类似的优化原则:尽量不要让 cell 自己承担那些可以在更高层级完成的重复工作。上层准备数据和交互上下文 → 下层 View 接收尽可能稳定、接近最终展示形式的值 → 与 rendering 无关的信息不要进入 SwiftUI observation/update graph。
排查 fastlane snapshot 多语言截图全部变成英语的问题 (Why your fastlane snapshot screenshots are all in English)
使用 fastlane snapshot 批量生成 App Store 多语言截图时,有时会遇到一个让人头痛的问题:语言目录都正确创建了,截图内容却全部显示为英语。真正麻烦的是,导致这一现象的原因并不唯一,排查起来也比较困难。
Manuel Lorenzo Parejo 列出了五个排查点:setupSnapshot 的调用时机;snapshot 的启动方式;localize_simulator;App Bundle 中是否包含对应的 .lproj;残留的 App 状态是否影响语言设置。同时还提供了免费的 shotfleet check 命令,通过识别截图文字并与 App 自身的本地化字符串进行比对,批量检查生成的截图是否真的使用了预期语言。
工具
Redlamp:一位摄影爱好者借助 AI 打造的原生 RAW 编辑器
Redlamp 是一款采用 Swift 和 Metal 开发的开源 macOS RAW 照片编辑器,使用 MPL-2.0 许可证,沿用了 Lightroom 用户熟悉的显影面板与操作习惯。作者 Pedro Gomes 既是一名工程师,也是一名摄影爱好者,一直希望有更多符合自己使用方式的工具选择。
在这个大量借助 AI 进行开发的项目中,仍能看到鲜明的个人意图与判断:Pedro 选择让照片库的数据库成为可重建的索引,将重要信息保存在照片旁;也会在测量发现蒙版边缘优化损失了细节后,收紧算法的适用范围。这些具体取舍,让 Redlamp 带有鲜明的作者印记。
项目博客记录了不少开发过程中的思考,代码库也公开了面向编程代理的协作规则与验证机制。Pedro 正在探索,如何让多个代理在持续迭代中参与复杂原生软件的开发,以及如何判断它们交付的成果是否可靠。
AnnotateIt:在 Mac 上完成从标注到 Create ML 训练的闭环
对想用 Create ML 训练自定义 Object Detection 模型的开发者来说,训练本身往往不是最麻烦的部分。真正耗时的是数据准备:Create ML 应用本身不提供标注功能,开发者通常需要借助其他工具画框,再将结果整理成 Create ML 可以使用的数据格式。
AnnotateIt 把这些步骤放进了同一个 Mac 应用。完成图片标注后,可以直接通过 Apple Create ML 在本地训练 Object Detector;训练得到的模型又可以用于新的图片和视频,辅助生成标注并由人工继续修正。对于 Swift 开发者而言,它不仅降低了尝试本地 Object Detection 的门槛,也把「标注 → 训练 → 预测 → 修正」连接成了一套完整的工作流。
在官方的停车场示例中,292 张图片的模型训练不到一分钟即可完成。整个过程不需要配置 Python 环境或云端 GPU,数据也可以始终留在本机。
InnoDI:让依赖图成为可验证的构建产物
Ethan Parker 开发的 InnoDI 是一套基于 Swift Macro 的依赖注入框架。它将对象图中原本需要手工编写的初始化与参数传递逻辑转化为显式的依赖声明,并生成容器初始化器和类型安全的测试替换接口。Macro 负责局部诊断,SPM Build Plugin 验证跨文件、跨模块的依赖图,配套 CLI 则可以对这张图进行检查和分析。
InnoSquad 的 InnoFlow、InnoRouter 和 InnoNetwork 也延续了类似思路,通过明确边界和可重复验证来减少隐式行为:把能够声明的约束提前声明,把运行时行为交给统一的执行策略管理。
在 AI Coding 时代,框架作者需要重新思考框架的消费者。“让开发者更容易编写代码”或许已不再是唯一的首要目标。当学习成本不再完全由人类开发者承担,“让代码的意图和行为更容易被验证”的重要性正在迅速提高。
SimAgentation:在浏览器中为 iOS 模拟器标注并交办 AI
使用 AI 调整界面时,如何准确表达“这里需要修改”,往往比描述修改本身更费力。citron 开发的 SimAgentation 让开发者在浏览器中操作 iOS 模拟器(IOSurface -> VideoToolbox -> WebCodecs),选中界面元素或框选区域,直接写下修改意见。工具会将反馈连同元素信息、源码搜索线索、整屏截图和局部截图,通过 MCP 交给编码助手,并在浏览器中显示处理状态。
可选的 SimAgentationPlus 则支持通过 .simTag() 为视图补充名称、文件和行号。这与我在 FlowCanvas 中采用的元素锚点思路有相通之处:将画面与结构化信息结合,让 AI 更准确地理解反馈对象。