4.总结
4.1 知识点

学习的主要内容

优点

缺点

主要用处

4.2 核心要点速览
PlayerPrefs 能干什么
- Unity 提供的静态工具类,用来按「键—值」读写玩家侧偏好数据(音量、新手引导标记、简单进度等)。
- 值类型被引擎限制在三种:
int、float、string;键一律是字符串。 - 需要存
bool、枚举、向量等,只能自己约定编码(例如bool用0/1写入SetInt)。
存储模型与常见坑
- 语义上就是键值对:一个
key对应一个槽位;后写入覆盖先写入,与这次用的是 SetInt 还是 SetFloat 无关。 - 若对同一
key先SetInt再SetFloat,再用GetInt去读,读到的往往不是旧整数,而是该类型的默认值(文中示例为0)。线上排障时,优先怀疑「键复用 + 类型混写」。 - 其它类型只能「降精度 / 升精度」再塞进这三种里,例如把布尔折成整数。
写入、内存与落盘
Set*先把改动放在内存里的偏好缓存中,不保证立刻落到磁盘。- 正常退出游戏时,Unity 会自动刷盘;进程崩溃、强杀时,未落盘改动可能丢失。
- 需要「改完马上落盘」(例如付费结果、关键进度),在合适的逻辑点调用
PlayerPrefs.Save()。
读取语义
- 只要在本进程里
Set过,即使还没Save,同一运行会话内Get也能拿到刚写入的值。 GetInt/GetFloat/GetString的重载:只传key时,找不到键会返回类型默认值(int为0,float为0f,string为"");传第二参数时,找不到键则返回你给的默认值,适合做「首次启动初始化」。HasKey用来判断某个键是否存在;不是用来替代默认值的——没有键时直接Get带默认参数往往更简单。文中强调它解决的是「有没有写过这个键」这类问题。
核心 API
| 分类 | API | 作用 | 默认 / 注意 |
|---|---|---|---|
| 写 | SetInt / SetFloat / SetString |
按 key 写入值 | 同 key 后写覆盖;类型混用再读会踩坑 |
| 刷盘 | Save |
把当前改动写入磁盘 | 崩溃前未 Save 可能丢;性能上不要每帧狂刷 |
| 读 | GetInt / GetFloat / GetString |
按键取值 | 单参版用类型默认;双参版用自定义默认 |
| 查 | HasKey |
键是否存在 | 不等价于业务「空值判断」 |
| 删 | DeleteKey |
删单个键 | |
| 删 | DeleteAll |
清空本应用偏好 | 慎用,调试外一般封装权限 |
各平台数据落在哪
| 平台 | 存放位置(文中表述) | 怎么理解 |
|---|---|---|
| Windows | 注册表 HKCU\Software\[公司名]\[产品名] |
公司名 / 产品名来自 Player 设置;编辑器下常见路径会经 Unity\UnityEditor\... 再落到项目配置的名字 |
| Android | /data/data/包名/shared_prefs/ 下的 xml |
与包名绑定;真机调试需要知悉权限与路径习惯 |
| iOS | /Library/Preferences/[应用ID].plist |
随应用沙盒走 |
键名设计与集合数据
- 不同语义的数据禁止共用一个 key,否则就是互相覆盖、静默丢数据。
- 多角色、多存档槽、多条排行榜记录,习惯用「前缀 + 业务字段后缀」拆键,例如
player1_name、rankScore0。 - 存
List:先写Count,再按索引循环写每一项的字段;读的时候按Count重建列表。练习里的玩家装备、排行榜条目都是这个套路。
4.3 面试题精选
基础题
1. PlayerPrefs 能直接存哪些类型
题目
PlayerPrefs 原生支持写入哪些 C# 类型?如果想存布尔值,一般怎么做?
深入解析
正文明确:只有 int、float、string 三种写入接口。键始终是 string。
布尔在业务里通常映射为 0/1(或 SetInt("flag", value ? 1 : 0)),读出来再还原。枚举可以强转成整数存。复杂结构不能一行 API 搞定,要自己设计编码或换存储方案。
答题示例
原生就三种:
int、float、string,键是字符串。布尔一般用
0和1走SetInt,读的时候再转成bool。
参考文章
- 2.基本方法
2. 只 Set 不 Save,当前运行里能不能读到
题目
调用 SetInt 后没有调用 PlayerPrefs.Save(),立刻 GetInt 能否拿到刚写的值?什么时候可能丢?
深入解析
文中结论:同一运行进程内,Set 后即使未 Save,Get 也能读到。持久化到磁盘发生在 Save 被调用或正常退出等时机;若进程异常结束,未落盘的改动可能丢失。
答题示例
能读到,因为改动先在内存偏好里,
Get读的是当前会话状态。真正写到磁盘要靠
Save或正常退出;崩溃、强杀时没落盘就可能丢,关键数据要显式Save。
参考文章
- 2.基本方法
3. 同一 key 混用 SetInt 与 SetFloat 会怎样
题目
先 PlayerPrefs.SetInt("k", 18),再 PlayerPrefs.SetFloat("k", 20.2f),接着 GetInt("k") 得到什么?说明原因。
深入解析
同一 key 只有一个槽位,后写入覆盖前写入。最终槽位里是按浮点写入的,再用 GetInt 去读时,与文中示例一致,会得到 int 的默认值 0(而不是 18 或 20 的整数部分这种「想当然」)。这题考的是「键唯一 + 类型匹配」意识。
答题示例
会得到
int的默认值0,因为同一个 key 被后面的SetFloat占掉了,再用GetInt读,类型对不上那条记录的预期,表现成默认。线上要避免同一 key 混用不同类型,团队内约定命名和读写封装。
参考文章
- 2.基本方法
进阶题
1. 什么时候必须考虑显式调用 Save
题目
既然退出时会自动写盘,为什么示例里仍在 Save() 方法末尾调用 PlayerPrefs.Save()?什么场景下你倾向于手动刷盘?
深入解析
自动刷盘依赖「正常退出」这条路径;崩溃、断电、移动端被系统杀进程时,内存里的偏好可能来不及写回。练习代码在存档方法末尾 Save,是在「玩家点保存、过关结算」这类关键节点强制落盘,降低丢失概率。工程上还要权衡频率:每帧 Save 会引入 I/O 压力,一般只在关键点调用。
答题示例
正常退出 Unity 会帮你写,但崩溃或强杀就不保险。
所以在存档、购买结果、重要进度变更后显式
Save,把风险压住;不要在高频逻辑里每帧刷。
参考文章
- 2.基本方法
2. Windows 上 PlayerPrefs 大致存在哪
题目
在 Windows 上,PlayerPrefs 数据主要落在什么系统机制里?路径里的公司名和产品名从哪来?
深入解析
正文给出注册表路径模板 HKCU\Software\[公司名称]\[产品名称],名称来自 Player 设置。编辑器下调试时,文中步骤经过 Unity\UnityEditor\... 再找到对应公司 / 产品节点。能答出「注册表 + 与 Player 配置绑定」即可;不要求背诵每一级子键在不同 Unity 版本上的细微差别。
答题示例
主要在注册表当前用户下,
Software里按公司名、产品名分层。名字是项目在 Player 设置里配的那两个字段;调设置、清存档时常要去注册表或等价存储里找对节点。
参考文章
- 3.不同平台的存储位置
3. HasKey 和带默认值的 Get 怎么分工
题目
什么时候用 HasKey,什么时候直接用 GetXxx(key, defaultValue) 就够了?
深入解析
文中强调:HasKey 判断「这个键有没有被写过」;Get 的第二参数负责「没有键时给业务默认值」。若逻辑是「从未存档过则用一套初始数值」,双参 Get 往往一次搞定。若你要区分「老玩家升级存档」和「全新安装」这类分支,HasKey 才有额外信息量。
答题示例
Get带默认值适合绝大多数初始化:没有键就用默认。
HasKey用在需要区分「是否存在过这条记录」的分支,不是用来替代默认值判空的。
参考文章
- 2.基本方法
深度题
1. 用 PlayerPrefs 做大型存档的主要短板
题目
练习里用 Count + 索引后缀 去模拟列表、排行榜;从工程角度,长期把大块、多变的游戏数据都塞进 PlayerPrefs,主要风险和成本是什么?
深入解析
系列正文只讲了 API、键唯一和「拆成多条键」的写法,没有规定何时必须换存储方案。结合这些前提能归纳:键会随列表变长而变多,改结构或删条目容易留下旧键;数据一复杂,读写逻辑分散,不如集中式存档易维护。面试里常再追问「那用什么替代」——JSON、二进制、SQLite 等是常见答案,但具体选型要看项目规模与平台,别把具体容量、加密细节说成 Unity 文档原文。
答题示例
PlayerPrefs 适合键值偏好和小块数据;列表要手写 count 和循环键,结构一变就要改键规则,还容易留下废弃键。
数据一大、结构一复杂,维护成本和踩键冲突风险都上去,一般会换成更集中的存档方案,而不是继续堆键。
参考文章
- 2.基本方法
- 3.不同平台的存储位置
2. 键名冲突的成因与规避
题目
文中说「同一项目里 key 相同会造成数据丢失」。多模块、多程序员协作时,你会怎么约定键名,避免互相覆盖?
深入解析
正文只给原则:唯一性由 key 决定,相同 key 即覆盖。工程上常见做法:模块前缀(Audio_、Quest_)、版本或存档槽后缀、集中常量类维护键字符串,禁止魔法字符串散落在各处。练习里 keyName + "_name" 也是前缀隔离思路的雏形。
答题示例
冲突根因是 PlayerPrefs 全局一个命名空间,后写覆盖先写。
用模块前缀、存档槽、常量类统一管 key,禁止各处硬编码同一短字符串;多角色就像练习里用
Player1_、Player2_这类前缀隔开。
参考文章
- 2.基本方法
- 3.不同平台的存储位置
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com