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

Generic struct 'ForEach' requires that '[String : [Any]]' conform to 'RandomAccessCollection'

Forums > SwiftUI

Hello i want to rewrite code from Swift to SwiftUI but i cant i got Generic struct 'ForEach' requires that '[String : [Any]]' conform to 'RandomAccessCollection' this is my. code

let content = try! String(contentsOf: myURL!, encoding: .ascii)
let test = content.data(using: .utf8)!
let dict = try! JSONSerialization.jsonObject(with: test) as? [String:[Any]]

View:

struct ContentView: View {
    private var test = dict
  var body: some View {
      List {
          ForEach(test!.indices, id: .self) { index in
              Text(index)

          }

      }

  }
}

Image: (if image doesnt show https://postimg.cc/xNGw49J7

1      

Dictionary doesn't conform to RandomAccessCollection.

It's a little hard to suggest alternative approaches with so little code to tell us just what you're trying to do. But I would suggest 1) use Codable instead of JSONSerialization, and 2) figure out what it is you're actually trying to list and use that instead of a Dictionary.

2      

Just sort the dictionary with something like - ForEach(item.sorted(by: >), id: \.key) { key, value in then do as you wish with key or value

1      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

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

i dont want to work with hardcoded datatypes(create struct...). because in json (each object has array) can be added new objects, (from database). and i want to read that objects from json. i want to rewrite the code to SwiftUI. i did that in swift correctly with this code:

example json:

    {
"Burgres": [
        {
            "food_name": "Hovadzi Burger",
            "food_description": "Najlepsi burger na svete, uhorka, cibula, majoneza, masko a tak dalej",
            "alergens": "1, 3, 6"
        },
    ],
    }

swift code :

func makeGetCall() {
    guard let myURL = URL(string: "xxxxxx") else {
        print("Error: \(String(describing: link)) doesn't seem to be a valid URL")
        return
    }

    do {
        let content = try String(contentsOf: myURL, encoding: .ascii)
        let test = content.data(using: .utf8)!
        if let dict = try JSONSerialization.jsonObject(with: test) as? [String:[Any]] {
               for k in dict{
                   print(k.key)

                   for i in k.value{

                       let tmp_i = i as! NSDictionary

                        for (k,v) in tmp_i
                        {

                            print("\(k):\(v)")
                        }

                        print("\n")
                   }
                   print("---------------------------\n")
               }

        }
    }
    catch {
        print(error)
    }
}

1      

can you try this , is this what you want ? no error so far , gives me Burgres in list

let dataFood = """
{
"Burgres": [
        {
            "food_name": "Hovadzi Burger",
            "food_description": "Najlepsi burger na svete, uhorka, cibula, majoneza, masko a tak dalej",
            "alergens": "1, 3, 6"
        },
    ],
    }

"""
    .data(using: .utf8)!

struct ContentView: View {

    private var test: [String: [Any]] = try! JSONSerialization.jsonObject(with: dataFood) as! [String:[Any]]
    var body: some View {

        List {
            ForEach(test.keys.sorted(), id:\.self) { index in
                      Text(index)

                  }

              }

    }

}

1      

@AmitShrivastava yes but what if i want to access food_name(variable and value and print it) in every object, in dictionary for example: food_name : Hovadzi Burger

update :


  let dataFood = """
{
"Burgres": [
        {
            "food_name": "Hovadzi Burger",
            "food_description": "Najlepsi burger na svete, uhorka, cibula, majoneza, masko a tak dalej",
            "alergens": "1, 3, 6"
        },
    ],
    }

"""
    .data(using: .utf8)!

struct Food: Codable, Hashable {
    let food_name : String
    let food_description : String
    let alergens : String
}

struct ContentView: View {
    //private var test: [String: [Any]] = try! JSONSerialization.jsonObject(with: dataFood) as! [String:[Food]]
    private var food = try! JSONDecoder().decode([Food].self, from: dataFood)
    var body: some View {

        List {
            ForEach(food, id: \.self) { index in
                Text("\(index.food_name)")

                  }

              }

    }

}```
but i got this ![](https://imgur.com/9B3nas6)
https://imgur.com/9B3nas6 if wont show

1      

@localhost - the error can be resolved by using

private var food = try? JSONDecoder().decode([Food].self, from: json)

ForEach(food ?? [], id: \.self)

But its not showing any thing on list, i tried a few things myself, but its not giving the results

1      

@AmitShrivastava Im trying something like this: but i get Generic struct 'ForEach' requires that '[Welcome : [Food]]?' conform to 'RandomAccessCollection

let content = try! String(contentsOf: myURL!, encoding: .ascii)
let test = content.data(using: .utf8)!
let dict = try! JSONSerialization.jsonObject(with: test) as? [Welcome:[Food]]

struct Food: Codable, Hashable {
    let name, Description, alergens: String

    enum CodingKeys: String, CodingKey {
        case name
        case Description = "description"
        case alergens
    }
}

struct Welcome: Codable, Hashable {
    let food_type: [Food]
}
struct ContentView: View {
    private var test = dict
    var body: some View {
        Text("Text")
            ForEach(test){ key in
                Text(key)
            }

    }
}

1      

In SwiftUI, ForEach will require that you give it a RandomAccessCollection. However, there are ways to iterate through a dictionary using ForEach if you know what all of the keys are, and can make a RandomAccessCollection out of them.

struct ContentView: View {
    let dictionary: [String: Int] = ["Hello": 1, "Hi": 2, "Hey": 3, "Wassup?": 4]

    let dictionaryKeys = ["Hello", "Hi", "Hey", "Wassup?"]

    var body: some View {
        List {
            ForEach(dictionaryKeys, id: \.self) { greeting in
                if let value = dictionary[greeting] {
                    Text("\(value)")
                }
            }
        }
    }
}

I don't know how helpful this will be in your case. But maybe it will be useful.

1      

You don't even need to know the keys beforehand:

ForEach(Array(dictionary.keys), id: \.self) { greeting in
    Text("\(dictionary[greeting]!)")
}

And, bonus, you don't need the check for a nil value since we know the key exists in the Dictionary.

Or, if you object to the force unwrap on principle or from an abundance of caution, you can enumerate the elements of the Dictionary:

ForEach(Array(dictionary.enumerated()), id: \.0) { (_, elem) in
    //elem is a (key, value) pair
    Text("\(elem.value)")
}

2      

Lol... I was trying to figure out how to use dictionary.keys instead, but couldn't think of how to make it into an array rather than a Set.

Easy, Array(dictionary.keys)!

Thanks. I don't know why I couldn't think of that.

1      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

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.