这个系列面向 Swift 初学者,目标是从零做出一个可运行的贪吃蛇小游戏。这一篇进入真正的界面代码阶段:先把游戏区域、单元格和信息栏的 UI 结构搭起来,再借 `UnitView` 这个最基础的组件,理解 `enum` 和 `struct` 在 Swift 里分别适合解决什么问题。
完整 Demo 地址:RickeyBoy/SnakeGame
笔记文章合集地址:RickeyBoy/Rickey-iOS-Notes
先把 UI 代码框架搭起来
这一阶段先处理 Layout 文件夹中的内容,也就是游戏界面相关的基础视图。按照文章给出的拆分方式,最终需要新建 3 个文件:

- GameView:游戏区域本体。
- UnitView:游戏区域中的每一个单位小格子。
- LogView:位于上方的信息展示区域。
这个拆法的好处很直接:游戏主区域、最小显示单元和状态信息栏职责分开,后面继续扩展逻辑时,不容易把绘制、布局和状态显示混在一起。
`UnitView` 要解决的两个核心问题
对于每一个小方格来说,最关键的其实只有两件事:

- 它在哪个位置,也就是坐标。
- 它现在显示什么,也就是格子的状态。
文章里将这两个问题拆得很清楚。坐标负责描述格子位置,状态负责决定格子的视觉表现。这样做之后,`UnitView` 的职责就会非常明确。
格子一共有 4 种显示状态
一个小格子会出现 4 种展示情况,对应不同的图形样式:
- 蛇头:展示绿色菱形
- 蛇身:展示绿色圆形
- 食物:展示星星
- 空白格子:不展示任何图片
因为这 4 种情况是固定且离散的,所以这里适合用 `enum` 表达:
/// UnitView 类型
enum UnitViewType {
case snakeHead /// 蛇头
case snakeBody /// 蛇身
case food /// 食物
case normal /// 空白格子
}
用枚举的直接收益是:状态集合天然收敛,不会在后续代码里出现随意拼写的“非法状态”,同时代码语义也更清晰。
坐标信息用 `struct` 表达更自然
坐标本质上是一组绑定的数据,这里只需要 `x` 和 `y` 两个整数即可,所以文章采用了 `struct`:
/// 坐标
struct Pos {
var x: Int
var y: Int
}
这种写法很适合表示“一个对象的若干属性组合”。在贪吃蛇这种网格类游戏里,位置数据会被频繁读取、比较和传递,用结构体封装会比零散地传 `x`、`y` 更利于维护。
为什么这里是 `enum` 配 `struct`
这一节也是文章真正想借项目带出的 Swift 基础知识点:`UnitViewType` 为什么用 `enum`,`Pos` 为什么用 `struct`。

在 Swift 中,除了常见的 `class`,`struct` 和 `enum` 也是高频出现的类型:
- struct(结构体):用于定义自定义数据类型,可以包含多个属性和方法。结构体是值类型。
- enum(枚举):用于定义一个有固定数量的常量集合,可以有原始值,也可以关联值。枚举可以定义方法。
| 特性 | struct | enum |
|---|---|---|
| 类型 | 自定义数据类型 | 固定数量的常量集合 |
| 存储 | 值类型 | 值类型(默认)或引用类型(如果定义为 class) |
| 属性 | 可以有多个属性 | 通常没有属性,但可以扩展 |
| 方法 | 可以定义方法 | 可以定义方法 |
| 原始值 | 不适用 | 可以有,用于存储额外信息 |
| 关联值 | 不适用 | 可以有,每个枚举案例可以关联不同的数据类型 |
| 继承 | 不能被继承 | 不能被继承 |
| 构造器 | 可以有构造器 | 可以有构造器 |
需要注意,原文中有一句“struct 由于是引用类型”,这一点和前文“结构体是值类型”并不一致。按照 Swift 的实际语义,struct 是值类型。也正因为它是值类型,才特别适合像坐标这样的轻量数据结构。
至于 `enum`,Swift 的枚举能力比很多语言更完整,不只是“列几个选项”这么简单,它还可以带方法、原始值和关联值。因此在状态建模上,`enum`` 往往比普通常量更清楚,也更安全。
放到贪吃蛇项目里,这样选型的理由是什么
回到这个项目本身,类型选择其实是按语义来的:
UnitViewType使用 `enum`,是因为它表示的是一组固定的离散状态,例如蛇头、蛇身、食物、空白格子。Pos使用 `struct`,是因为它表示的是一组紧密绑定的数据,也就是 `x` 和 `y` 这两个坐标值。
换句话说,前者是在描述“它属于哪一种”,后者是在描述“它有哪些数据”。这也是 Swift 项目里很常见的一条判断标准。
可以这样快速判断使用场景
`enum` 的应用场景:用来定义有限的选项集,比如状态、类型、选项,语义明确且类型安全。
`struct` 的应用场景:适合表示简单的数据结构,也就是若干属性的组合,同时具备值语义,整体更轻量。
对于正在学 Swift 的读者来说,这一节的价值不只是“把贪吃蛇的一个格子写出来”,更重要的是开始形成建模习惯:先分清状态和数据,再决定应该用 `enum` 还是 `struct`。
这一阶段完成了什么
这一篇虽然还在 UI 起步阶段,但已经把后续代码最基础的两个抽象搭好了:
- 界面层面,明确了 `GameView`、`UnitView`、`LogView` 三个组件的分工。
- 数据层面,明确了 `UnitView` 至少需要“位置”和“状态”这两类信息。
后面继续实现时,就可以在这个基础上逐步补齐绘制逻辑、状态变化和游戏运行流程。













