0

Let's say I'm trying to parse this particular JSON file with SwiftUI:

data.json

[
    {
        "number": 1,
        "word": "hello",
        "sentence": {
            "word_one": "my",
            "word_two": "name"
            "word_three": "is"
            "word_four": "jeff"
        }
    },
    {
        "number": 2,
        "word": "there",
        "sentence": {
            "word_one": "i",
            "word_two": "dream"
            "word_three": "about"
            "word_four": "cheese"
        }
    }
]

I understand how to parse number and word, but what I'm having trouble with is how to parse everything in sentence. I am new to iOS programming and the resources I've been looking at are confusing to me. This is the code I have thus far:

struct Content: Codable, Hashable {
    let number: Int
    let word: String
}

struct ContentView: View {
    func jsonParse() -> [Content] {
            let url = Bundle.main.url(forResource: "data", withExtension: "json")!
            let data = try! Data(contentsOf: url)
            let decoder = JSONDecoder()
            let products = try? decoder.decode([Content].self, from: data)
            return products!
        }
    
    var body: some View {
        NavigationView {
            List {
                ForEach(jsonParse(), id: \.self) { content in
                    VStack(alignment: .leading, spacing: 0) {
                        Text("\(content.word)")
                    }
                }
            }
        }
    }
}

Thank you for your help!

7
  • 1
    Your JSON data contains two dictionaries, which are not number and word. Commented Aug 9, 2021 at 3:00
  • @ElTomato Is there something I'm doing wrong with my struct? Commented Aug 9, 2021 at 3:10
  • You could declare sentence as a dictionary [String:String] Commented Aug 9, 2021 at 3:13
  • @Paulw11 How would I then create text with sentence on the ContentView? Would it be something like Text("\(content.sentence.word_one)")? Commented Aug 9, 2021 at 3:18
  • No, You will need to get the keys of the dictionary and sort the array and then iterate over the sorted array for keys and access the value for key in dictionary.keys.sorted { Text(dictionary[key]) kind of thing; I would put the keys and sorting behind a computed variable in your model and use ForEach Commented Aug 9, 2021 at 3:52

2 Answers 2

1

First, your JSON data is invalid. It should be the following.

[
    {
        "number": 1,
        "word": "hello",
        "sentence": {
            "word_one": "my",
            "word_two": "name",
            "word_three": "is",
            "word_four": "jeff"
        }
    },
    {
        "number": 2,
        "word": "there",
        "sentence": {
            "word_one": "i",
            "word_two": "dream",
            "word_three": "about",
            "word_four": "cheese"
        }
    }
]

No. 2, read your data as follows.

import UIKit

struct Content: Decodable {
    let number: Int
    let word: String
    let sentence: Sentence
}

struct Sentence: Decodable {
    let word_one: String
    let word_two: String
    let word_three: String
    let word_four: String
}

Finally, read your JSON file in the bundle as follows.

if let path = Bundle.main.path(forResource: "jsonData14", ofType: "json") {
   if let jsonData = readFileContent(path: path) {
      do {
         let result = try JSONDecoder().decode([Content].self, from: jsonData)
         print(result)
         
         } catch let error as NSError {
         print("\(error)")
      }
   }
}
Sign up to request clarification or add additional context in comments.

Comments

0

Hi as El Tomato pointed out your JSON is invalid. I used the fixed JSON that was provided from El Tomato.

If you simply want the answer here it is.

import SwiftUI

struct ContentView: View {
    let json = """
[
    {
        "number": 1,
        "word": "hello",
        "sentence": {
            "word_one": "my",
            "word_two": "name",
            "word_three": "is",
            "word_four": "jeff"
        }
    },
    {
        "number": 2,
        "word": "there",
        "sentence": {
            "word_one": "i",
            "word_two": "dream",
            "word_three": "about",
            "word_four": "cheese"
        }
    }
]
""".data(using: .utf8)!
    var body: some View {
        Text("Hello, world!")
            .padding()
            .onAppear(perform: decode)
    }
    
    func decode() {
        let decoder = JSONDecoder()
        
        do {
            let result = try decoder.decode(Content.self, from: json)
            print(result)
        } catch {
            print(error)
        }
        
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

// MARK: - ContentElement
struct ContentElement: Codable {
    let number: Int
    let word: String
    let sentence: Sentence
}

// MARK: - Sentence
struct Sentence: Codable {
    let wordOne, wordTwo, wordThree, wordFour: String
    
    enum CodingKeys: String, CodingKey {
        case wordOne = "word_one"
        case wordTwo = "word_two"
        case wordThree = "word_three"
        case wordFour = "word_four"
    }
}

typealias Content = [ContentElement]

I use a program called quicktype and it prepopulates the structs you'll need to decode JSON. I apologize I can't explain further because I too don't know.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.