jsonswiftdecode

Trying to decode a JSON value that can be a String or Int


Trying to decode a JSON value "edition" that can be a String or Int and found this solution How to decode JSON value that can be either string or int which gives me an error "Candidate requires that 'SavedFavBooksFromISBN.Edition' conform to 'PersistentModel' (requirement specified as 'Value' : 'PersistentModel')"

Can anyone assist with how to decode this value that can be String or Int?

Code is below

import Foundation
import SwiftData

struct Response: Decodable {

    let bookObjects: [SavedFavBooksFromISBN]
}

@Model class SavedFavBooksFromISBN: Decodable, Identifiable, Hashable {

    private(set) var id: String
    private(set) var title: String
    private(set) var language: String?
    private(set) var edition: Edition
    
    init(id: String, edition: Edition, language: String?, title: String) {
        
        self.id = id
        self.title = title
        self.language = language
        self.edition = edition
    }
        
    enum Edition: Decodable {
        case int(Int)
        case string(String)
    }
    
    enum CodingKeys: String, CodingKey {
        case id = "isbn13"
        case title
        case language
        case edition
    }
    
    required init(from decoder: any Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        title = try container.decode(String.self, forKey: .title).trunc(length: 1500)
        id = try container.decode(String.self, forKey: .id)
        language = try container.decodeIfPresent(String.self, forKey: .language)
        if let value = try? container.decode(Int.self, forKey: .edition) {
            self.edition = .int(value)
        } else if let value = try? container.decode(String.self, forKey: .edition) {
            self.edition = .string(value)
        } else {
            let context = DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Unable to decode value for `edition`")
            throw DecodingError.typeMismatch(Edition.self, context)
        }
    } //end init
}

struct BookDataStore: Decodable {

    var books: [SavedFavBooksFromISBN]
}

Solution

  • for a model to be Decodable, you need to have all your structs and enums properties to conform to Codable, so use this to fix your error:

     enum Edition: Codable {
         case int(Int)
         case string(String)
     }