0

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

Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278
E.YILDIRIM
  • 49
  • 6
  • 3
    Does this answer your question? [Using codable with value that is sometimes an Int and other times a String](https://stackoverflow.com/questions/47935705/using-codable-with-value-that-is-sometimes-an-int-and-other-times-a-string). Also type names should start with an upper case letter, so HarryPotter and Wand. And you should be able to figure out the second error quite easily since you have a struct Wand... – Joakim Danielson Aug 23 '20 at 13:15

1 Answers1

0

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]
Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278
  • thanks. I want to ask one more question. When I export the data in yearOfBirth to an array, how do I define the array? String or Int ? It will be give error – E.YILDIRIM Aug 23 '20 at 14:03
  • I don't see the point in making the type into an enum of different types like YearOfBirth, this will only lead to issues when handling the property. Sort of using Any for type but with some restrictions. – Joakim Danielson Aug 23 '20 at 15:02
  • @E.YILDIRIM like this: `[YearOfBirth]` – Mojtaba Hosseini Aug 23 '20 at 15:09
  • @JoakimDanielson enum is the best answer for different known types. I don't know the reason of this specific json but maybe it was better to define a custom decoder to decode it and convert to Int right in the initializer. Otherwise, enum is the best. – Mojtaba Hosseini Aug 23 '20 at 15:11
  • Looking at this particular json the strings always seems to be empty so to me it looks like they represent a nil value. – Joakim Danielson Aug 23 '20 at 15:14
  • I totally agree with you in this @JoakimDanielson – Mojtaba Hosseini Aug 23 '20 at 15:18