Search code examples
iosjsonswift

Swift JSON Type Mismatch


There is two mismatch error . First one because of yearOfBirth variable. Because one of JsonData is String ("") although others are Integer.

Second one is wand variable. Error is:

Expected to decode String but found a dictionary instead

My model is :

struct harryPotter : Codable{
    var name : String
    var species : String
    var gender : String
    var house : String
    var dateOfBirth : String
    var yearOfBirth : Int
    var ancestry : String
    var eyeColour : String
    var hairColour : String
    var wand : String
    var patronus : String
    var hogwartsStudent : Bool
    var hogwartsStaff : Bool
    var actor : String
    var alive : Bool
    var image : String
}

struct wand : Codable{
    var wood : String
    var core : String
    var length : Int
 }

JSON Data Link : JSON


Solution

  • The error clearly tells that the wand type should be Wand instead of String.

    Also, for variables with multiple types, you can use enums.

    Also, for options like gender, you should use enum instead.

    So:

    import Foundation
    
    // MARK: - Input
    struct Input: Codable {
        let name: String
        let species: Species
        let gender: Gender
        let house, dateOfBirth: String
        let yearOfBirth: YearOfBirth
        let ancestry, eyeColour, hairColour: String
        let wand: Wand
        let patronus: String
        let hogwartsStudent, hogwartsStaff: Bool
        let actor: String
        let alive: Bool
        let image: String
    }
    
    enum Gender: String, Codable {
        case female = "female"
        case male = "male"
    }
    
    enum Species: String, Codable {
        case cat = "cat"
        case halfGiant = "half-giant"
        case human = "human"
        case werewolf = "werewolf"
    }
    
    // MARK: - Wand
    struct Wand: Codable {
        let wood, core: String
        let length: Length
    }
    
    enum Length: Codable {
        case double(Double)
        case string(String)
    
        init(from decoder: Decoder) throws {
            let container = try decoder.singleValueContainer()
            if let x = try? container.decode(Double.self) {
                self = .double(x)
                return
            }
            if let x = try? container.decode(String.self) {
                self = .string(x)
                return
            }
            throw DecodingError.typeMismatch(Length.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for Length"))
        }
    
        func encode(to encoder: Encoder) throws {
            var container = encoder.singleValueContainer()
            switch self {
            case .double(let x):
                try container.encode(x)
            case .string(let x):
                try container.encode(x)
            }
        }
    }
    
    enum YearOfBirth: Codable {
        case integer(Int)
        case string(String)
    
        init(from decoder: Decoder) throws {
            let container = try decoder.singleValueContainer()
            if let x = try? container.decode(Int.self) {
                self = .integer(x)
                return
            }
            if let x = try? container.decode(String.self) {
                self = .string(x)
                return
            }
            throw DecodingError.typeMismatch(YearOfBirth.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for YearOfBirth"))
        }
    
        func encode(to encoder: Encoder) throws {
            var container = encoder.singleValueContainer()
            switch self {
            case .integer(let x):
                try container.encode(x)
            case .string(let x):
                try container.encode(x)
            }
        }
    }
    
    typealias Inputs = [Input]