您应该创建一个结构体或枚举来组织您的键,因为您的方式很容易出现拼写错误。只需将其放在班级上方即可
enum Key: String {
case allSettings
case lightEnabled
case soundEnabled
}
而不是像这样调用按键
...forKey: Key.lightEnabled.rawValue)
现在关于你的问题,我在尝试保存 40 个级别的属性(最佳时间、级别解锁状态等)时遇到了同样的问题。我最初做了你尝试过的事情,这纯粹是疯狂的。
我最终使用数组/字典甚至字典数组来存储数据,这将我的代码减少了 80% 左右。
这样做的好处是,你需要保存像 LevelUnlock bools 这样的东西,它会让你以后的生活变得更加轻松。就我而言,我有一个 UnlockAllLevels 按钮,现在我可以循环遍历我的字典/数组并在几行代码中更新/检查 levelUnlock 布尔值。比使用大量 if-else 或 switch 语句来单独检查每个属性要好得多。
例如
var settingsDict = [
Key.lightEnabled.rawValue: false,
Key.soundEnabled.rawValue: false,
...
]
比在解码器方法中你这样说
注意:这种方式将考虑到您可能会向 SettingsDict 添加新值,并且在下一次应用程序启动时这些值不会被删除,因为您不会用保存的字典替换整个字典,您只更新已经存在的值存在。
// If no saved data found do nothing
if var savedSettingsDict = decoder.decodeObjectForKey(Key.allSettings.rawValue) as? [String: Bool] {
// Update the dictionary values with the previously saved values
savedSettingsDict.forEach {
// If the key does not exist anymore remove it from saved data.
guard settingsDict.keys.contains($0) else {
savedSettingsDict.removeValue(forKey: $0)
return
}
settingsDict[$0] = $1
}
}
如果您使用多个字典,那么您的解码器方法将再次变得混乱,并且您还将重复很多代码。为了避免这种情况,您可以使用泛型创建 NSCoder 的扩展。
extension NSCoder {
func decodeObject<T>(_ object: [String: T], forKey key: String) -> [String: T] {
guard var savedData = decodeObject(forKey: key) as? [String: T] else { return object }
var newData = object
savedData.forEach {
guard object.keys.contains($0) else {
savedData[$0] = nil
return
}
newData[$0] = $1
}
return newData
}
}
然后您可以在每个字典的解码器方法中编写此代码。
settingsDict = aDecoder.decodeObject(settingsDict, forKey: Key.allSettings.rawValue)
您的编码器方法将如下所示。
encoder.encodeObject(settingsDict, forKey: Key.allSettings.rawValue)
在您的游戏/应用程序中,您可以像这样使用它们
settingsDict[Key.lightEnabled.rawValue] = true
if settingsDict[Key.lightEnabled.rawValue] == true {
/// light is turned on, do something
}
这种方式使得集成 iCloud KeyValue 存储变得非常容易(只需创建一个 iCloud 字典),这主要是因为它可以轻松地用很少的代码保存和比较大量值。
UPDATE:
为了使调用这些更容易一些,我喜欢在 GameData 类中创建一些方便的 getter/setter。这样做的好处是您可以更轻松地在项目中调用这些属性(就像您的旧方法一样),但您的编码/解码方法仍然保持紧凑。您还可以执行诸如循环比较值之类的操作。
var isLightEnabled: Bool {
get { return settingsDict[Key.lightEnabled.rawValue] ?? false }
set { settingsDict[Key.lightEnabled.rawValue] = newValue }
}
var isSoundEnabled: Bool {
get { return settingsDict[Key.soundEnabled.rawValue] ?? false }
set { settingsDict[Key.soundEnabled.rawValue] = newValue }
}
你可以像普通属性一样称呼它们。
isLightEnabled = true
if isLightEnabled {
/// light is turned on, do something
}