更新保存的可编码结构以添加新属性



我的应用程序使用可编码的结构,如下所示:

public struct UserProfile: Codable {
var name: String = ""
var completedGame: Bool = false
var levelScores: [LevelScore] = []
}

JSONEncoder()已用于将UserProfile的编码数组保存到用户默认值。

在即将进行的更新中,我想向此UserProfile结构添加新属性。这在某种程度上可能吗?

或者我是否需要创建一个具有相同属性和一个新属性的新可编码结构,然后将所有值复制到新结构,然后开始使用该新结构来代替以前使用UserProfile结构的任何位置?

如果我只是向结构添加一个新属性,那么我将无法加载以前的编码数组UserProfiles,因为结构将不再具有匹配的属性。当我到达用于加载已保存用户的以下代码时:

if let savedUsers = UserDefaults.standard.object(forKey: "SavedUsers") as? Data {
let decoder = JSONDecoder()
if let loadedUsers = try? decoder.decode([UserProfile].self, from: savedUsers) {

如果UserProfile编码和保存时具有的属性不包含UserProfile结构的所有当前属性,则loadedUsers不会解码。

更新保存的结构属性有什么建议吗?还是我必须走很长的路并重新创建,因为我之前还没有提前计划包含此属性?

感谢您的任何帮助!

如注释中所述,您可以将新属性设置为可选,然后解码将适用于旧数据。

var newProperty: Int?

另一种选择是在解码期间应用默认值(如果缺少属性(。

这可以通过在结构中实现init(from:)

来完成
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
completedGame = try container.decode(Bool.self, forKey: .completedGame)
do {
newProperty = try container.decode(Int.self, forKey: .newProperty)
} catch {
newProperty = -1
}
levelScores = try container.decode([LevelScore].self, forKey: .levelScores)
}

这要求您定义一个CodingKey枚举

enum CodingKeys: String, CodingKey {
case name, completedGame, newProperty, levelScores
}

如果不希望它在代码中使用时是可选的,则第三个选项是将其包装在计算的非可选属性中,再次使用默认值。这里_newProperty将在存储的 json 中使用,但newProperty用于代码

private var _newProperty: Int?
var newProperty: Int {
get {
_newProperty ?? -1
}
set {
_newProperty = newValue
}
}

最新更新