Displaying JSON data in SwiftUI

Thank you, Rooster.

This is the entire ForEach loop:

      ForEach(todo, id: \.self) { item in
                        HStack {
                            Text("userID: 
                            \(item.userID)\nID: 
                            \(item.id)\nTitle: 
                            \(item.title)\nCompleted: 
                            \(item.completed ? "True" : "False")")
                            Spacer()
                        }
                        Divider()
                    }

You can’t break a String across multiple lines like that if you’ve used single to mark it. You need to use either a multiline String delimited with triple quotes ””” or make your String single line and replace the line breaks with \n.

1 Like

@dav_leda

Have you got it working now?

No, I’m still getting a blank screen on the simulator :confused:

@dav_leda

OK first of all did you change the ForEach so that the contents are EXACTLY as per the following:

ForEach(todo, id: \.self) { item in
    HStack {
        Text("userID: \(item.userID)\nID: \(item.id)\nTitle: \(item.title)\nCompleted: \(item.completed ? "True" : "False")")
        Spacer()
    }
    Divider()
 }

When I say exactly, I mean copy the above and past it into your project exactly as it is. Don’t try reformatting the line so that the data items line up under each other in the editor window because that won’t work. You cannot split up a string across multiple lines as Roosterboy pointed out.

Are you getting any error messages in the Debug Console?

Hi Chris,

Yes, the code is exactly the same, except that I replaced

ForEach(todo, id: \.self)

with:

ForEach(todo)

Otherwise I get the following error: “Type ‘()’ cannot conform to ‘View’; only struct/enum/class types can conform to protocols”.

I didn’t split up that line in the Text field, it’s exactly as you quoted.

I’m not getting any error messages in the Console, just a blank screen, both in the console and the simulator (except for the navigation bar that reads “SwiftUI Example”).

Hmmmm, I don’t know what is going on.

Here is a link to my version of the project. See if that runs on your Mac in the same simulator.

Thank you for the zip. I tried it but got the same result.

Please send me a screenshot of your simulator running the code. Thanks.

This is what I get:

This is my screenshot with exactly the same code. The fact that I am using Xcode 12 should not make any difference as the target build is iOS 13.6.

This is crazy that yours is not working.

I would be tempted to delete and then re-install Xcode. If you have a developer account you can download Xcode 11.7 from this page.

https://developer.apple.com/download/more/

It doesn’t work for me on Xcode 11.7. I see the same result that @dav_leda is reporting.

(I did have to add a couple of self. and replace @main with @UIApplicationMain in the AppDelegate to get it to build on 11.7.)

If I stick a print call in the decoding block like so:

            do {
                let loaded = try decoder.decode([ToDo].self, from: data!)
                print(loaded)
                DispatchQueue.main.async {
                    self.todo = loaded
                }
            } catch {
                print("Unable to decode JSON from \(url!)")
            }

I can see that loaded is getting populated but it’s not getting assigned to self.todo in the DispatchQueue operation.

I’ve run out of time to work on this tonight, though. I can take it up again tomorrow or maybeyou can figure it out from these clues?

Ah right. Good points Patrick. I overlooked the self requirement in closures and clean forgot that Xcode 12 uses @main in the AppDelegate. Damn.

Hi Chris,

So this means that I have to install Xcode 12 in order to run your code?

I tried downloading Xcode 12 from the App Store but I get an error message:

This is weird cause I have almost 35GB of disk space on my HD:

On another note, thank you for sending your screenshot. The result is very similar to what you would get if you used the List method, but my question was actually about how to display one single element of the Array, that’s why I wanted to avoid using List. I guess my questions were kind of confusing. Sorry about that, I’m not yet familiar with the coding language (plus, English is not my native language).

When you download Xcode it requires more disk space than the size of the download file. It will decompress (expand) the file and use up a lot of temporary file space on your hard drive as it goes through the installation process. The Mac Operating System is also using disk space as temporary memory “swap in swap out” space too so yes, despite it saying you have 35Gb, that seems like it is not enough. Also it’s a good idea to shut down every other program so that the only thing running is the update.

To be honest I would not be going to the extent of installing Xcode 12 unless you absolutely need to because, as far as I can tell, there is nothing in my ContentView.swift that requires Xcode 12. If you plan on eventually submitting Apps to the App Store then you will need the latest Xcode.

If you create a new project in Xcode 11.7 and then copy the contents of my ContentView (from the earlier post) and paste it in place of the ContentView code in your new project, I thought it should work.

I’m a little puzzled why it does not.

Interestingly, if I replace

            ScrollView {
                VStack(spacing: 10) {
                    ForEach(todo) { item in
                        HStack {
                            Text("userID: \(item.userID)\nID: \(item.id)\nTitle: \(item.title)\nCompleted: \(item.completed ? "True" : "False")")
                            Spacer()
                        }
                        Divider()
                    }
                }
                .padding(.horizontal)
            }

with

            List(todo, id: \.id) { item in
                HStack {
                    Text("userID: \(item.userID)\nID: \(item.id)\nTitle: \(item.title)\nCompleted: \(item.completed ? "True" : "False")")
                    Spacer()
                }
            }

then it works for me.

Maybe a bug in Xcode 11.7 (Swift 5.2.4) involving ScrollView?

Aha, and not five minutes later I find this thread at the Ray Wenderlich forums:

So it looks like ScrollView can’t be initialized with an empty array, at least not in Xcode 11.7.

If I alter the body property like so:

    var body: some View {
        NavigationView {
            Group {
                if !todo.isEmpty {
                    ScrollView {
                        VStack(spacing: 10) {
                            ForEach(todo) { item in
                                HStack {
                                    Text("userID: \(item.userID)\nID: \(item.id)\nTitle: \(item.title)\nCompleted: \(item.completed ? "True" : "False")")
                                    Spacer()
                                }
                                Divider()
                            }
                        }
                        .padding(.horizontal)
                    }
                }
                else {
                    Text("")
                    //I tried to put EmptyView() here but it just kept crashing
                }
            }
            .navigationBarTitle("SwiftUI Example")
            .onAppear() {
                self.populateArray()
            }
        }
    }

then it works as expected. You do get a flash of the View from the else clause, but that could be worked around with an empty Text (as I did) or maybe a Color or a loading message or whatever you want.

Cheers Patrick. I wish I still had Xcode 11.7 installed.