UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: JSON decoding not working

Forums > Swift

Hi All,

I'm new to the forums and Swift and have been following along closly with Paul's tutorials, however I seem to run into a problem that I cannot solve. The issue is that I am running a JSON decoder that is the same as Paul's tutorials so I can get used to how decoding works and when I use the hardcoded JSON test everything is fine, however when I place the same contents into a json file the decoder is never able to decode the JSON and it falls into the fatalError section but alas with no error that I can read as a human. I will post my code here and hopfully someone can help me figure out either A how to get a readable error or B how to get it working, ideally both. I have check the JSON file is in the bundle :)

Swift code is as follows:

struct JData: Codable  {

    let name: String
    let address: Addr

}

struct Addr: Codable  {
    let street: String
    let city: String
}

extension Bundle {
    func decode<T: Codable>(_ file: String) -> T {
        guard let url = self.url(forResource: file, withExtension: nil) else {
            fatalError("Failed to locate \(file) in bundle.")
        }

        guard let data = try? Data(contentsOf: url) else {
            fatalError("Failed to load \(file) from bundle.")
        }

        let decoder = JSONDecoder()

        guard let loaded = try? decoder.decode(T.self, from: data) else {
            //print(error.localizedDescription)
            fatalError("Failed to decode \(file) from bundle.")
        }

        return loaded
    }
}

let JD: [String: JData] = Bundle.main.decode("proj.json")

print(JD)

JSON in file is as follows:

{
  "name": "Nigel",
  "address": {
    "street": "1 Any Road",
    "city": "Anytown"
  }
}

Thanks in advance for any help!

3      

hi,

i would think you want

let JD: JData = Bundle.main.decode("proj.json")

what you have in JSON looks to be a single instance of JData.

hope that helps,

DMG

3      

You'll get better errors if, instead of this:

guard let loaded = try? decoder.decode(T.self, from: data) else {
    //print(error.localizedDescription)
    fatalError("Failed to decode \(file) from bundle.")
}

you do this:

do {
    let loaded = try decoder.decode(T.self, from: data)
    return loaded
} catch {
    print(error)
    fatalError(error.localizedDescription)
}

try? returns an Optional result and turns any error into nil, which swallows them up and hides the exact error from you.

3      

Thank you both for your help!

DMG your suggestion really did help me howver some fault lay in my JSON too however I am still struggling to use the parsed data but its a challenge I'm hoping to solve soon.

Thank you to roosterboy too, understanding the errors returned has really helped me to narrow down where the actual problem lies.

3      

Hi Everyone,

Hope you are all well, since posting this topic I have managed to make progress with my test project however I seem to have run into another stumbling block which is confusing me and I hope someone maybe able to advise me.

The issue is that I can successfully decode my JSON and load it how I need too, howver I am not able to load a single item from a sub array in my JSON code, in essence I am trying to recreate the messages app to familerise myself with differant ways of working etc.

I have a ForEach block that creates a NavLink item for all the test users by name and then my JSON code is split at the messages section into individual messages. My JSON looks like this:

[
    {
        "id": 1,
        "Age": "25",
        "Message": [
            {
                "id": 101,
                "content": "Est amet quia optio nobis vero qui dolorum distinctio sint accusamus quis velit dignissimos. Et maiores earum velit odit ducimus non enim ut recusandae sunt. Ut eos aut ipsa ut natus porro et. Molestias laboriosam atque provident voluptatem."
            },
            {
                "id": 102,
                "content": "POP WOOSH BANG Est amet quia optio nobis vero qui dolorum distinctio sint accusamus quis velit dignissimos. Et maiores earum velit odit ducimus non enim ut recusandae sunt. Ut eos aut ipsa ut natus porro et. Molestias laboriosam atque provident voluptatem."
            }
        ],
        "Name": "Helen",
        "Phone": "01002993321"
    }
 ]

I have followed Pauls tutorials on the Moonshot tutorial but I cannot seem to access just a single message (eg id 101) to display in a preview in the nav link and the closest I've gotten is to have a preview both of the messages using a ForEach in my ForEach which is not exactly ideal, furthermore I would also like to pass this information through to a detail view to show the full list of messages also like the messages app. Could any body help me with this please? Even an explanation of how to go about it would be good as I will have an idea how to go from there.

Thanks in advance!

3      

hi,

the JSON you have now describes an array of elements (only one is shown in the JSON above), whose element description could be

struct DataElement: Codable {
  var id: Int
  var Age: String
  var Message: [MessageElement]
  var Name: String
  var Phone: String
}

where the MessageElement type is itself a struct:

struct MessageElement: Codable {
  var id: Int
  var content: String
}

you would read this into your program using

let myArray: [DataElement] = Bundle.main.decode("<your file name here>")

all messages can be printed using

for element in myArray {
  for messageElement in element.Message {
    print("id: \(messageElement.id)  \(messageElement.content)")
  }
}

we don't see any SwiftUI code above, but i would guess you have a list of DataElement, with navigation links to the messages associated with each DataElement.

var body: some View {
  List {
    ForEach(myArray) { element in
      NavigationLink(destination: NextView(element.MessageElement)) {
        // your description of what to print for the element here
      }
    }
  }
}

and then NextView has a similar ForEach to show each of the messages.

hope that helps,

DMG

3      

Hi DMG,

Thank you very much for your reply, I appreciate the help you have given me.

I intentionally left out my code as at the time I couldn't for the life of me pass the array through to the next view, howver my code was already pre confugured exactly as yours up until the first For loop you hinted at... THAT was the break through I needed, I knew XCode was unhappy about me sending the array through to the next view but its eronious erors were no help what-so-ever, I then tried (unsuccessfully) to pass part of the array through containing the actual messages but then I ran into out of range errors when some of the JSON messages were only singular ones.

Your code has really helped me parse through to just what I need to pass through and I now have a greater understanding of how I need to navigate my way through nested arrays in arrays and I am thankful for your clear explinations as for me that is the most important thing... learning, sure others can give you example code to help but for me its about being pointed in the right direction and to actually code my own way out of the problem or even to be told you can't do this in this way. I knew decoding my JSON more than once was not the answer to this even though it may of made my life easier.

Thank you again every one for your help, having a friendly warm and open forum to ask advise really does help and I hope that one day I'll be able to help ohers as I have been helped too.

Merry Christmas/Happy Holidays to all that celebrate!

Nigel

3      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.