iOS 开发为什么普遍不用“拖拉拽”可视化 UI#

Jobs出品,必属精品


🔥 前言#

先纠正一个容易误解的前提:现代 iOS 开发不是“完全不用可视化 UI”,而是很多中大型项目不再把 Storyboard / XIB 当作页面结构的唯一事实来源。现在更常见的是“代码声明界面 + 实时预览 + 自动化验证”,其中 SwiftUI 本身就是这种变化的代表。

拖拉拽解决的是“快速摆出一个界面”;工程团队真正长期面对的,却是多人协作、需求变化、组件复用、动态布局、代码审查、自动化测试和跨版本维护。两者关注的问题不在同一个尺度上。

一、四种 UI 方式先分清 🔼 🔽#

1.1、它们不是“可视化”和“代码”两个简单阵营#

方式界面的主要事实来源可视化能力常见定位
StoryboardXML 场景图、约束、SegueInterface Builder小型应用、原型、流程固定的页面
XIB单个 View / Controller 的 XMLInterface Builder独立视图、历史 UIKit 项目
纯代码 UIKitSwift / Objective-C 源码运行、Debug View Hierarchy、第三方预览高度动态、组件化或历史大型项目
SwiftUI声明式 Swift 源码Xcode Preview新功能、跨 Apple 平台、状态驱动 UI

Storyboard 和 XIB 仍由 Xcode 支持;“大家不用拖拉拽”通常只是团队在架构上的取舍,不是 Apple 删除了这条开发路线。

1.2、SwiftUI 不是“没有可视化”,而是可视化方式变了#

SwiftUI 把界面结构写在源码中,Preview 再把结果实时渲染出来。开发者可以在源码、预览、控件库和属性检查器之间联动,但最终可审查、可合并的事实仍然是代码。

这相当于把过去的:

拖控件 → 改 XML → 运行后确认

变成:

声明 View → Preview 即时反馈 → 测试和源码共同验证

二、中大型项目为什么偏向代码式 UI#

2.1、XML 能比较,但不容易“读懂变化”#

Storyboard / XIB 本质上仍是 XML 文件。移动一个控件、改一次约束或让 Xcode 升级文档格式,都可能同时改变对象 ID、层级、Frame 和元数据。

代码式 UI 的差异通常更接近人的意图:

VStack(spacing: 12) {
    titleView
    submitButton
}

代码审查者能直接看出“新增了什么、删掉了什么、布局参数为什么变化”。这不代表代码永远没有冲突,而是冲突通常更容易定位、拆分和讨论。

2.2、多人同时修改同一张画布,合并成本高#

一个 Storyboard 可能同时承载多个页面、Segue 和共享对象。两个人只要改到同一个 XML 文件,就可能发生冲突;Git 能指出文本冲突,却不知道哪一个控件关系才是产品意图。

团队可以通过“每个页面一个 Storyboard”降低冲突,但继续拆分之后,它已经逐渐接近代码组件化的管理方式。

2.3、真实页面不是一张固定海报#

商业 App 常同时面对:

  • 不同 iPhone / iPad 尺寸、横竖屏和分屏。
  • 动态字体、VoiceOver、粗体文本和辅助功能尺寸。
  • 中文、英文、阿拉伯语等不同文本长度和书写方向。
  • 登录态、会员态、AB 实验、远端配置、空态、异常态和骨架屏。
  • 列表复用、分页、异步数据和局部刷新。

Interface Builder 可以表达 Auto Layout,但当页面结构本身由状态决定时,代码通常更直接。SwiftUI 更进一步,把“状态改变后界面应该长什么样”写成声明。

2.4、组件化需要清楚的输入、输出与依赖#

拖出来的控件容易依赖 Outlet、Segue、Storyboard ID 和隐式生命周期。规模变大后,调用方需要记住很多“画布之外的约定”。

代码组件更容易明确:

  • 初始化需要哪些数据。
  • 哪些状态由组件自己维护,哪些由外部注入。
  • 用户事件通过闭包、Delegate、Binding 还是 Action 回传。
  • 样式、无障碍标识和埋点在哪一层统一。

这也是设计系统、模块化和可复用组件更偏爱源码表达的原因。

2.5、自动化测试和持续集成更喜欢确定性#

代码式 UI 可以被编译器、Lint、单元测试、Snapshot Test、UI Test 和 CI 一起检查。Storyboard 也会参与构建,但很多连接错误要到运行或加载场景时才暴露,例如 Outlet 失效、复用标识不一致、场景类名变化等。

SwiftUI Preview 还能构造多组静态状态,用较低成本同时查看深色模式、动态字体、语言和设备尺寸。Preview 不是测试的替代品,但能让视觉反馈更靠近源码修改时刻。

2.6、导航和依赖注入不应藏在一根连线里#

Storyboard Segue 对简单跳转很直观,但复杂工程通常需要:

  • 登录拦截与深链恢复。
  • A/B 路由和模块解耦。
  • 父子流程编排。
  • 页面依赖注入与可测试替身。

当跳转规则成为业务逻辑后,显式 Router / Coordinator 或 Navigation 状态,比散落在画布里的连线更容易追踪。

三、拖拉拽 UI 仍然适合什么场景#

3.1、不是落后,而是要用在合适的尺度#

下列场景继续使用 Storyboard / XIB 完全合理:

  • 产品原型、教学 Demo、一次性验证。
  • 页面数量少、结构稳定、协作者很少的应用。
  • 设计师或初学者需要快速建立控件与约束直觉。
  • 历史项目已有成熟的 Storyboard 分包、代码审查和测试规范。
  • 单个可复用 UIKit View 用 XIB 表达,边界明确且不频繁变动。

问题不在“拖拉拽”三个字,而在于是否把一个会长期演进的复杂系统,压进一张越来越难合并和审查的画布。

3.2、Interface Builder 仍有自己的优势#

  • 约束关系和层级能直接观察。
  • 对固定表单和静态页面,初始搭建速度快。
  • 不运行完整 App 就能看到大致结构。
  • Size Class、Safe Area、Stack View 等能力仍可视化配置。

所以合理结论不是“纯代码一定高级”,而是:团队应按页面动态程度、协作规模和维护周期选择事实来源。

四、为什么很多团队从 Storyboard 迁出#

4.1、常见的真实触发点#

触发点表面现象根因
合并冲突频繁XML 冲突难判断多页面共享同一文件
启动或页面加载慢大 Storyboard 初始化成本上升场景和对象图过大
复用困难同一组件被复制多份组件边界与输入不明确
线上状态复杂画布只有一套静态样子UI 由运行时状态决定
测试困难必须加载整个场景构造函数和依赖隐式化
模块拆分困难Storyboard ID 跨模块耦合路由和所有权没有显式接口

4.2、迁移不应该一次推倒重来#

更稳妥的路线是:

1、先停止继续扩大单个 Storyboard。

2、把新增页面写成独立的 SwiftUI 或代码式 UIKit 组件。

3、用 UIHostingController、容器控制器等方式让新旧页面共存。

4、优先迁移冲突最频繁、状态最复杂、测试收益最大的页面。

5、保留已经稳定且维护成本低的 XIB / Storyboard,不为了形式统一强拆。

五、团队应该怎样选#

5.1、一张简单决策表#

问题偏向 Storyboard / XIB偏向代码 UIKit / SwiftUI
页面是否高度动态
是否多人并行修改
是否跨模块复用
是否要求状态预览和快照测试
团队现有能力IB 流程成熟代码架构成熟
项目剩余生命周期短且稳定长期迭代

5.2、Jobs 式结论#

现代 iOS 团队减少拖拉拽,不是因为可视化“不专业”,而是因为:

页面在设计阶段像一张图,在工程阶段却是一个会被多人持续修改、由数据驱动、需要测试和版本管理的程序。

代码式 UI 把结构、状态和变化收敛到同一套可审查事实中;SwiftUI Preview 又把可视化反馈补回来。今天真正的趋势不是“可视化消失”,而是“可视化从 XML 画布,迁移到以代码为源的实时预览”。

六、官方资料#

我是有底线的➤点我回到首页