[swift-users] Robust Codable coding

Kyle Murray kyle_murray at apple.com
Fri Jun 23 20:24:57 CDT 2017


Hi Howard,

If I'm understanding your question correctly, you're asking: What happens if you remove, for example, the comment property in v2 of your Project structure?

The way you've set things up lets you remove all references to comment in your code, and it can still exist as a key in old data that works with the v2 code. The old key will just be ignored. 

struct Project: Codable {
    var ecsVersion = 0

    init() {}

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        ecsVersion = try values.decodeIfPresent(Int.self, forKey: .ecsVersion) ?? ecsVersion
    }
}

let json = """
{
    "ecsVersion": 7,
    "comment": "A test comment."
}
""".data(using: .utf8)!

let decoded = try? JSONDecoder().decode(Project.self, from: json)
print(decoded as Any) // Prints "Optional(Project(ecsVersion: 7))"


---

If you still want comment to exist in your struct, but you don't want it to be sourced from an old saved file any longer, you just need to remove the decodeIfPresent line for that property. There isn't any CodingKeys exhaustiveness checking going on because you're not using the compiler-synthesized initializer.

Hope this helps,
Kyle

> On Jun 23, 2017, at 5:36 PM, Howard Lovatt via swift-users <swift-users at swift.org> wrote:
> 
> Hi All,
> 
> I have started to use Codable and was looking for some advice. I want to make the persisted data structure robust so that if I change the properties as the code develops the new code can deserialise an old saved file. This is what I am currently doing:
> 
> 
> struct Project: Codable {
>     var ecsVersion = 0
>     var comment = ""
>     
>     init() {}
>     
>     init(from decoder: Decoder) throws {
>         let values = try decoder.container(keyedBy: CodingKeys.self)
>         ecsVersion = try values.decodeIfPresent(Int.self, forKey: .ecsVersion) ?? ecsVersion
>         comment = try values.decodeIfPresent(String.self, forKey: .comment) ?? comment
>     }
> }
> 
> The idea is that if I add fields the deserialisation doesn’t fail provided that I provide a default value. However this presumably fails when you delete a field because CodingKeys is now incorrect. (I say presumably because the documentation doesn’t say what will happen.) Though not ideal, I can leave disused properties in Projects to prevent the deserialisation error.
> 
> Any advice? Is there a better way?
> 
> Thanks in advance,
> 
>  — Howard.
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170623/96c8609d/attachment.html>


More information about the swift-users mailing list