NEW: Start my new Ultimate Portfolio App course with a free Hacking with Swift+ trial! >>

ForEach View not updating

Forums > SwiftUI

@Cryv  

Hello guys, I'm really starting to hating SwiftUI cause for me it never works when i think it should.. But maybe I'm just not good enough.

I'm trying to update a simple list based on an array situated on the model, but the view won't update. Here is the relevant code:

The cose might miss some parenthesis cause it is not copied exactly, only the needed parts for you to understand.

Thank you to anyone who might help me!

struct Model {
var ticket: [Item] = []
}
class Controller: ObservableObject {
    @Published var model = Model()

    var viewContext = PersistenceController.shared.container.viewContext

    var ticketItems: [Item] {
        get {
            posViewModel.ticket
        }
    }

    func addItemToTicket(withName name: String, price: Double) {
        let item = Item(context: viewContext)
        item.name = name
        item.price = price
        item.id = UUID()
        model.ticket.append(item)
    }
}

struct View: View { @StateObject controller = Controller()

var body: some View { TicketView(controller: controller) } }

 struct TicketView: View {
 @State var controller: Controller

 var body: some View {
        List {
            ForEach(controller.ticketItems, id:\Item.id) { (item: Item) in
                Text(item.name!)
            }
        }
    }
  }
  struct AnotherView: View {
   @State var controller: Controller
  Button {
    controller.addItemToTicket(label: "", price: 0)
  }
  }

   

You should be using StateObject instead of State for an ObservableObject.

https://developer.apple.com/documentation/swiftui/stateobject

   

You should try this.

a ForEach work that you require that you have array or simlar to look ForEach(Array the , id: requires that KeyValue that unique to that item ForEach(Array, id: \.id) (you might not need this if the class/struct is Identifiable)and in the closure the property refer to the Individual items in the array (this can be left out if using $0.name for instant).

struct TicketView: View {
  var controller: Controller

  var body: some View {
        List {
            ForEach(controller.ticketItems) { item in
                Text(item.name ?? "No Item") // assuming you forced unwarp due to Coredata!
            }
        }
    }
  }

as you passing in controller to TicketView()

struct View: View { 
  @StateObject controller = Controller()

  var body: some View { 
  TicketView(controller: controller) 
  } 
}

   

@Cryv  

Thank you guys, I tried all of what you said, still doesn't work. I fixed it using @EnvironmentObject and injecting it from the parent view but now it broke again..

   

    var ticketItems: [Item] {
        get {
            posViewModel.ticket
        }
    }

Where does posViewModel come from? It's not a property of your Controller object from what you've posted.

Also, how are your items being fetched from Core Data? Please include that code so we can verify that it's correct.

   

@Cryv  

class PosViewController: ObservableObject {
  @Published var posViewModel = PosViewModel()

  var ticketItems: [Item] { get { posViewModel.ticket }}
 }
struct PosViewModel {
    let persistenceController = PersistenceController.shared
    let container: NSPersistentContainer
    let viewContext: NSManagedObjectContext

    var categories: [Category] = []
    var selectedCategory: Int = 0

    var ticket: [Item] = []
    var total = 0.0

    init() {
        container = persistenceController.container
        viewContext = container.viewContext

        let request = NSFetchRequest<Category>(entityName: "Category")
        request.sortDescriptors = [NSSortDescriptor(keyPath: \Category.name, ascending: true)]

        do {
            categories = try viewContext.fetch(request)
          } catch let error as NSError {
            print("Could not fetch. \(error), \(error.userInfo)")
          }
    }
}

Anyway I solved the problem by using ForEach instead of List, but still this is a problem I can't figure out

   

Hacking with Swift is sponsored by RevenueCat

SPONSORED Building and maintaining in-app subscription infrastructure is hard. Luckily there's a better way. With RevenueCat, you can implement subscriptions for your app in hours, not months, so you can get back to building your app.

Try it for free

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

Reply to this topic…

You need to create an account or log in to reply.

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.