.enumerated() method not working on array

Viewed 1284

I am passing data to a ForEach and had no problems until I used the .enumerated() method. I got the error that:

  1. Generic struct 'ForEach' requires that 'EnumeratedSequence<[String]>' conform to 'RandomAccessCollection'

  2. Type 'EnumeratedSequence<[String]>.Element' (aka '(offset: Int, element: String)') cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols

As for the first error then you'll see in the code that I'm just passing in an array. So I don't understand this error.

As for the second error I'm not sure about this one.

The data being passed into the array is fed from UserDefaults as you'll see in the code below.

import SwiftUI

struct ContentView: View {
    
    @State private var name = ""
    @State private var myArray = [String]()
    @State private var isShowing = false
    @State private var actionSheet = false
    let defaults = UserDefaults.standard
   
    var body: some View {
        VStack {
            Spacer()
            TextField("Insert name", text: $name)
                .padding()
            ScrollView(.horizontal) {
                HStack {
                    ForEach(myArray.enumerated(), id: \.self) { index, name in
                        Circle()
                            .onTapGesture {
                                self.actionSheet.toggle()
                            }
                            .frame(width: 50, height: 50)
                            .actionSheet(isPresented: $actionSheet) {
                                ActionSheet(title: Text("Titles"), message: Text("This is the message"), buttons: [
                                                .default(Text("Delete item")){
                                                    var loaded =  defaults.stringArray(forKey: "myData")
                                                    
                                                }
                                ])
                            }
                    }
                }.padding()
                
            }
            Text(String(myArray.count))
                .font(.system(size: 30, weight: .black, design: .rounded))
                .foregroundColor(.green)
            VStack {
                Button(action: {self.isShowing.toggle() }){ Text("Show")}
                if isShowing {
                    ForEach(myArray, id: \.self) { name in
                    Text(name)
                    }
                }
            }.animation(.interactiveSpring())
            Spacer()
            
            HStack {
                Button(action: {
                   
                    
                }){
                    Text("Delete")
                        .fontWeight(.bold)
                        .padding()
                        .foregroundColor(.white)
                        .background(Color.red)
                        .cornerRadius(10)
                }
                Button(action: {
                    myArray.append(name)
                    defaults.set(myArray, forKey: "myData")
                    self.name = ""
                }){
                    Text("Save")
                        .fontWeight(.bold)
                        .padding()
                        .foregroundColor(.white)
                        .background(Color.blue)
                        .cornerRadius(10)
                }
               

            }
           

        }.onAppear {
            guard let loaded = defaults.object(forKey: "myData") as? [String] else {
                return
            }
            self.myArray = loaded
        }
    }
}

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

Text

2 Answers

ForEach expects a type conforming to RandomAccessCollection, but Array.enumerated() returns an EnumeratedSequence<[Element]>, which only conforms to Sequence.

You can wrap it in an Array to get an array, which conforms to RandomAccessCollection:

ForEach(Array(myArray.enumerated()), id: \.1) { (n, element) in
}

I personally like to use zip

ForEach(zip(myArray.indices, myArray), id: \.1) { (index, element) in
}

because it works with non-integer indices as well.

The enumerated() returns sequence of tuples, which you can convert to array, like

HStack {
    ForEach(Array(myArray.enumerated()), id: \.1) { index, name in
        Circle()
Related