Search code examples
jsonswift

Fatal error: Failed to decode .json data from app bundle


import Foundation

struct RGBValue: Codable {
    let blue, green: Double
    let timestamp: String
    let red: Double
}

struct RGB: Codable {
    let fps: Double
    let heartRate: Int
    let rgbValues: [RGBValue]
    
    static let rgbData: [RGB] = Bundle.main.decode(file: "hrv_data.json")
    static let sampleData: RGB = rgbData[0]
}




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! error : \(Error.self)")

        }
        return loadedData
    }
}

This is the entire code snippet which shows no error, but while run time it crashes "Thread 1: Fatal error: Could not decode hrv_data.json in the project! error : Error" How to solve the issue and know the reason behind this error?

json sample:

{
  "fps": 0.1548667699098587,
  "heartRate": 81,
  "rgbValues": [
    {
      "blue": 0,
      "green": 0,
      "timestamp": "22-04-2024 10:33:57",
      "red": 0
    }
  ]
}

Solution

  • I really appreciate Paul Hudson's huge effort for the Swift community, but this Bundle extension he suggests to decode a JSON file is a poor advice, I'm afraid.

    It's highly recommended to catch always the comprehensive DecodingError, it tells you exactly what's wrong and even where the error occurred.

    Replace

    let loadedData = try? decoder.decode(T.self, from: data) else {
            fatalError("Could not decode \(file) in the project! error : \(Error.self)")
    }
    return loadedData
    

    with

    do {
        return try decoder.decode(T.self, from: data) 
    } catch {
        fatalError("Could not decode \(file) in the project! Error: \(error)")
    }
    

    The error is clear. The root object is a dictionary (note the enclosing {}), it's not an array

    static let sampleData: RGB = Bundle.main.decode(file: "hrv_data.json")