Swift 贪吃蛇 UI 起步:从 `UnitView` 设计看 `enum` 与 `struct` 的用法

纸上星河
纸上星河
发布时间:2026-08-22 | 200人浏览过
原创

前言

做 Swift 入门项目时,很多人一上来就急着写界面和逻辑,结果组件职责、状态表达和数据结构很快搅在一起。这一篇用贪吃蛇里的 `UnitView` 当例子,先把 UI 文件拆分清楚,再顺着“格子状态”和“坐标数据”两个问题,讲明白为什么这里该用 `enum` 和 `struct`,读完就能判断这种建模方式是否合理。

这个系列面向 Swift 初学者,目标是从零做出一个可运行的贪吃蛇小游戏。这一篇进入真正的界面代码阶段:先把游戏区域、单元格和信息栏的 UI 结构搭起来,再借 `UnitView` 这个最基础的组件,理解 `enum` 和 `struct` 在 Swift 里分别适合解决什么问题。

完整 Demo 地址:RickeyBoy/SnakeGame

笔记文章合集地址:RickeyBoy/Rickey-iOS-Notes

先把 UI 代码框架搭起来

这一阶段先处理 Layout 文件夹中的内容,也就是游戏界面相关的基础视图。按照文章给出的拆分方式,最终需要新建 3 个文件:

展示 Swift 贪吃蛇 UI 层的三个核心视图及其分工关系
贪吃蛇 UI 结构拆分用结构图梳理 `GameView`、`UnitView`、`LogView` 的职责划分。
  • GameView:游戏区域本体。
  • UnitView:游戏区域中的每一个单位小格子。
  • LogView:位于上方的信息展示区域。

这个拆法的好处很直接:游戏主区域、最小显示单元和状态信息栏职责分开,后面继续扩展逻辑时,不容易把绘制、布局和状态显示混在一起。

`UnitView` 要解决的两个核心问题

对于每一个小方格来说,最关键的其实只有两件事:

展示 UnitView 的四种状态与坐标数据如何组合成一个格子模型
UnitView 的最小建模方式把 `UnitView` 拆成“状态 + 坐标”两部分,再配合 4 种显示形态。
  1. 它在哪个位置,也就是坐标。
  2. 它现在显示什么,也就是格子的状态。

文章里将这两个问题拆得很清楚。坐标负责描述格子位置,状态负责决定格子的视觉表现。这样做之后,`UnitView` 的职责就会非常明确。

格子一共有 4 种显示状态

一个小格子会出现 4 种展示情况,对应不同的图形样式:

  1. 蛇头:展示绿色菱形
  2. 蛇身:展示绿色圆形
  3. 食物:展示星星
  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 中 struct 与 enum 的定位,并标出本项目里的实际用法
`struct` 与 `enum` 的选型判将 `struct` 和 `enum` 的常见用途与本文案例对应起来,帮助初学者理解为什么。

在 Swift 中,除了常见的 `class`,`struct` 和 `enum` 也是高频出现的类型:

  • struct(结构体):用于定义自定义数据类型,可以包含多个属性和方法。结构体是值类型。
  • enum(枚举):用于定义一个有固定数量的常量集合,可以有原始值,也可以关联值。枚举可以定义方法。
特性structenum
类型自定义数据类型固定数量的常量集合
存储值类型值类型(默认)或引用类型(如果定义为 class)
属性可以有多个属性通常没有属性,但可以扩展
方法可以定义方法可以定义方法
原始值不适用可以有,用于存储额外信息
关联值不适用可以有,每个枚举案例可以关联不同的数据类型
继承不能被继承不能被继承
构造器可以有构造器可以有构造器

需要注意,原文中有一句“struct 由于是引用类型”,这一点和前文“结构体是值类型”并不一致。按照 Swift 的实际语义,struct 是值类型。也正因为它是值类型,才特别适合像坐标这样的轻量数据结构。

至于 `enum`,Swift 的枚举能力比很多语言更完整,不只是“列几个选项”这么简单,它还可以带方法、原始值和关联值。因此在状态建模上,`enum`` 往往比普通常量更清楚,也更安全。

放到贪吃蛇项目里,这样选型的理由是什么

回到这个项目本身,类型选择其实是按语义来的:

  • UnitViewType 使用 `enum`,是因为它表示的是一组固定的离散状态,例如蛇头、蛇身、食物、空白格子。
  • Pos 使用 `struct`,是因为它表示的是一组紧密绑定的数据,也就是 `x` 和 `y` 这两个坐标值。

换句话说,前者是在描述“它属于哪一种”,后者是在描述“它有哪些数据”。这也是 Swift 项目里很常见的一条判断标准。

可以这样快速判断使用场景

`enum` 的应用场景:用来定义有限的选项集,比如状态、类型、选项,语义明确且类型安全。

`struct` 的应用场景:适合表示简单的数据结构,也就是若干属性的组合,同时具备值语义,整体更轻量。

对于正在学 Swift 的读者来说,这一节的价值不只是“把贪吃蛇的一个格子写出来”,更重要的是开始形成建模习惯:先分清状态和数据,再决定应该用 `enum` 还是 `struct`。

这一阶段完成了什么

这一篇虽然还在 UI 起步阶段,但已经把后续代码最基础的两个抽象搭好了:

  • 界面层面,明确了 `GameView`、`UnitView`、`LogView` 三个组件的分工。
  • 数据层面,明确了 `UnitView` 至少需要“位置”和“状态”这两类信息。

后面继续实现时,就可以在这个基础上逐步补齐绘制逻辑、状态变化和游戏运行流程。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表