Home > Mobile >  Can't Decode JSON successfully from file (Swift)
Can't Decode JSON successfully from file (Swift)

Time:09-30

O.

I have a JSON file in my XCode project. Lets use this as an example:

{ "shifts": [ 
  {"name": "Mary", 
    "role": "Waiter"},
    {"name": "Larry", 
    "role": "Cook"} 
    ] 
 }

In my JSONManager.swift, I have something along the lines of this:

struct Shift: Codable {
    let role, name: String
    
    static let allShifts: [Shift] = Bundle.main.decode(file: "shifts.json")
}


extension Bundle {
    func decode<T: Decodable>(file: String) -> T {
        guard let url = self.url(forResource: file, withExtension: nil) else {
            fatalError("Could not find \(file) in the project")
        }
        
        guard let data = try? Data(contentsOf: url) else {
            fatalError("Could not load \(file) in the project")
        }
        
        let decoder = JSONDecoder()
        
        guard let loadedData = try? decoder.decode(T.self, from: data) else {
            fatalError("Could not decode \(file) in the project")
        }
        
        return loadedData
    }
}

I keep hitting the fatalError("Could not decode \(file) in the project") and I'm wondering if it's because the JSON is not formatted correctly or why it can't decode the JSON from the JSON file.

CodePudding user response:

I fixed my own mistake. I don't need the

{ "shifts": }

in my JSON

CodePudding user response:

Take a look at you JSON structure for a momement.

You have a element called shifts, which is any array of other elements, but your code seems to trying to load a structure which only contains the child element.

Instead, you need a outer struct which contains the child struct, for example...

struct Shift: Codable {
    let role, name: String
}

struct Shifts: Codable {
    let shifts: [Shift]
}

Then you'd use the parent struct as the initial source type when decoding the content...

extension Bundle {
    func decode<T: Decodable>(file: String) -> T {
        guard let url = self.url(forResource: file, withExtension: nil) else {
            fatalError("Could not find \(file) in the project")
        }
        
        guard let data = try? Data(contentsOf: url) else {
            fatalError("Could not load \(file) in the project")
        }
        
        let decoder = JSONDecoder()
        
        guard let loadedData = try? decoder.decode(T.self, from: data) else {
            fatalError("Could not decode \(file) in the project")
        }
        
        return loadedData
    }
}

let shifts: Shifts = Bundle.main.decode(file: "shifts.json")

I tested this in playgrounds and it worked fine.

There might be away to decode the structure without needing the "parent" struct, but this works for me.

  • Related