前言:好久不更了,怪自己懒散了,总结一个小功能算是个经验吧,有关存储方案的。
本地存储不仅考虑数据合理性,也要考虑存储压力,权衡利弊实施最适合的方案才是最重要的。
需求描述
- 每个开关控制着一个语音的播报
- 开关记录存储到本地
功能实现
最简单直接的方法就是存一个model,记录每条数据的状态
{
"voice": "rabbit",
"status": 1
}
{
"voice": "rabbit",
"status": 0
}
{
"voice": "rabbit",
"status": 1
}
{
"voice": "rabbit",
"status": 0
}
{
"voice": "rabbit",
"status": 1
}
{
"voice": "rabbit",
"status": 0
}
{
"voice": "rabbit",
"status": 1
}
存储优化
开关状态只有「开/关」,可以想到用「0/1」标识,so灵感来了
- 每个语音设置一个标志位
- 每个标志位,0标识关,1标识开
声音种类 | 标志位 | 存储值 |
---|---|---|
小萝卜 | 0b00000001 | 1 |
小白菜 | 0b00000010 | 2 |
小土豆 | 0b00000100 | 4 |
小菜椒 | 0b00001000 | 8 |
小南瓜 | 0b00010000 | 16 |
小地瓜 | 0b00100000 | 32 |
小白兔 | 0b01000000 | 64 |
对应视觉图内存储存储结果应该是
二进制 | 存储值 |
---|---|
0b01000011 | 67 |
只需要存储一个【数值】,即可标志所有开关的组合,即各类组合值为 「2^N」
「0」表示所有开关关闭; 「127」表示所有开关打开
举个例子🌰:
存储值 | 小萝卜 | 小白菜 | 小土豆 | 小菜椒 | 小南瓜 | 小地瓜 | 小白兔 |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
23 | 0 | 0 | 1 | 0 | 1 | 1 | 1 |
98 | 1 | 1 | 0 | 0 | 0 | 1 | 0 |
… | … | … | … | … | … | … | … |
127 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
取值设置状态(按位与)
开关状态 = 预存值 & 标志位
开关状态 = 0b 01000011(预存值) & 0b00000100(小土豆) = 0(关)
语音置开(按位或)
语音置开 = 预存值 | 标志位
语音置开 = 0b 01000011(预存值) | 0b00000100(小土豆) = 0b 01000111(新预存值=71)
语音置关(按位异或)
语音置关 = 预存值 ^ 标志位
异或【^】:同为0、异为1
语音置关闭 = 0b 01000011(预存值) ^ 0b01000000(小白兔) = 0b 00000011(新预存值=3)
TODO
如果后续增加语音开关,只需要增加相关标志值即可,其他逻辑不需要修改
但枚举值必须满足「2^N」
Swift 对位运算兼容不是很友好,用十进制数字位运算也能达到效果。
总结
存储结构由一个model变成了一个数字,虽然在取值赋值操作逻辑稍微繁琐了一些,但降低了存储数据的量级,直接避免了I/O 操作,也算是特殊场景存储的最佳方案了。
蛮想念那个曾经我爱不释手的离散数学课