0

I have some static data for a list of "Badges" that I'm able to parse with JSONDecoder. I want to add a state that is not in the json data and when I added the variable to the Badge struct, parsing failed.

I then tried to create a two different structs, BadgeData which is parsed and Badge which contains state variable and BadgeData. But how do I merge this with state variable in a good way? Is there a better structure for this?

import Foundation


final class ModelData: ObservableObject {
    @Published var badges: [Badge] = // ??
    
    var badgeData: [BadgeData] = load("badges.json")
    var taken: [Int] = load("taken.json")
}

struct BadgeData: Hashable, Codable, Identifiable {
    let id: Int
    
    let title: String
    let imageRef: String
    let requirements: [Requirement]
}

struct Badge: Hashable, Codable, Identifiable {
    let data: BadgeData
    var id: Int {
        data.id
    }
    
    var isTaken: Bool
}

struct Requirement: Hashable, Codable, Identifiable {
    var id: Int
    
    let title: String
    let detail: String
}
norq
  • 1,404
  • 2
  • 18
  • 35
  • 2
    Create a CodingKey enum containing the keys you want the decoder to include when decoding the json. And also give your isTaken property a default value. https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types – Joakim Danielson Oct 21 '22 at 08:06

1 Answers1

1

when I added the variable to the Badge struct, parsing failed.

You need coding keys.

Defining coding keys allows you to determine which properties you get from JSON and which are ignored

struct Badge: Hashable, Codable, Identifiable {
    let id: Int
    
    let title: String
    let imageRef: String
    let requirements: [Requirement]
    
    var isTaken: Bool

    enum CodingKeys: String, CodingKey 
    {
    case id
    case title
    case imageRef
    case requirements
    }
}

The cases in CodingKeys map one to one to the properties you want to deserialise from the JSON.

Note also, that CodingKeys has a raw type which is String. This means that you can have different keys in your JSON to the property names e.g.

    enum CodingKeys: String, CodingKey 
    {
    case id
    case title
    case imageRef = "image_ref"
    case requirements
    }

would mean that the imageRef property in the object comes from the image_ref property in the JSON.

JeremyP
  • 84,577
  • 15
  • 123
  • 161