skip to Main Content

I would like to add a Product to a Shop‘s container but i can’t and i don’t understand why because my Shop is var and not let.
My goal is to put a Product into a Shop like this:
input Shop(name: "Apple Store", container: [])
output: Shop(name: "Apple Store", container: [Product(name: "Cheese")])

Here is My code:

import SwiftUI


struct Shop: Identifiable {
    let name: String
    var container: [Product]
    var id = UUID()
}

struct Product: Identifiable {
    let name: String
    var id = UUID()
}

struct ContentView: View {
    
    @State var shops: [Shop] = [
        Shop(name: "Apple Store", container: []),
        Shop(name: "StopShop", container: [Product(name: "milk")])
    ]
    
    var body: some View {
        NavigationView {
            List {
                ForEach(shops) { shop in
                    NavigationLink(shop.name, destination: {
                        List {
                            ForEach(shop.container) { product in
                                Text(product.name)
                            }
                        }
                        .navigationBarTitle(shop.name)
                        .navigationBarItems(trailing: Button {
                            shop.container.append(Product(name: "Cheese"))
                        } label: {
                            Text("add").bold()
                        })
                    })
                }
            }
            .navigationBarTitle("Shops")
        }
    }
}


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

I have tried by append or insert it and i expected it to work but it didn’t. 🙁

2

Answers


  1. Your problem here is that you are not modifying the struct’s

    @State var shops: [Shop]
    

    You are trying to change the element iterated on the foreach, which is, in fact, a let.

    ForEach(shops) { shop in // shop here is a let
    

    Knowing that, you should be able to modify your code to make the proper implementation.

    So for example, if you want to modify the struct’s param, you can:

    ForEach(Array(shops.enumerated()), id: .offset) { index, element in
      // ...
      shops[index].container.append(Product(name: "Cheese"))
    }
    

    (This is a draft example, you can do it however you think its best)

    Login or Signup to reply.
  2. The error tells the truth: Index variables in a loop are constants in Swift (since the initial release).

    Due to value semantics you have to modify the Shop element in the shops array directly.

    Add a function inside the view

    func appendProduct(_ product: Product, to shop: Shop) {
        guard let index = shops.firstIndex(where: {$0.id == shop.id}) else { return }
        shops[index].container.append(product)
    }
    

    and call it

    .navigationBarItems(trailing: Button {
        appendProduct(Product(name: "Cheese"), to: shop)
    } label: {
        Text("add").bold()
    })
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search