beowulf
beowulf

Reputation: 556

List item is not being updated

So I have a View with List of subviews that take an object. These objects come from array that is in my data manager.

struct ContentView: View {
@ObservedObject var manager = AppConnectivityManager.shared

var body: some View {
    
        List {
            ForEach(manager.goals, id: \.id) { goal in
                let _ = print("goal in foreach: \(goal.goal.completitionCount) + title: \(goal.goal.title)")
                GoalView(goalWrapper:goal)
            }.listRowBackground(Color.clear)
        }
    
    }
}

This part works well and update is triggered every time I update the manager object.

The problem is that my GoalView(goalWrapper:goal) gets only updated once when the code runs first time but then when its supposed to be refreshed it stays the same. This print("progress: statement in the goal view prints always the same values but the print statement in the list gets the updates. I might be missing the concept but I though I can pass the ObservedObject down the subview and it will get updated when manager gets also updated but that is not the case.

struct GoalView: View {

@ObservedObject var goalWrapper: GoalWrapper

var body: some View {
    let _ = print("progress: \(self.goalWrapper.goal.completitionCount) + daily: \(self.goalWrapper.goal.dailyNotificationCount) + title: \(self.goalWrapper.goal.title)")
    ZStack(content: {
        GoalAnimationView(goalWrapper: self.goalWrapper).cornerRadius(10)
        VStack(alignment: .leading, spacing: nil, content: {
            Text(goalWrapper.goal.title).foregroundColor(.black).padding(.leading, 8)
                .padding(.trailing, 8)
                .padding(.top, 4)
            HStack(alignment: .center,content: {
                Text("\(goalWrapper.goal.completitionCount)/\(goalWrapper.goal.dailyNotificationCount)").padding(.top, 2).padding(.trailing, 85).padding(.bottom, 6)
                Text("\(goalWrapper.goal.completitionCount)").padding(.top, 2).padding(.trailing, 12).padding(.bottom, 12).font(.title)
            }).frame(minWidth: 0, maxWidth: .infinity, minHeight: 0,maxHeight: 35,alignment: .trailing).background(Color.clear)


        }).listRowPlatterColor(Color.blue).frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, alignment: .leading).cornerRadius(10)
        
    })
  }
}

Here is the GoalWrapper class

public class GoalWrapper: ObservableObject, Hashable {

    public static func == (lhs: GoalWrapper, rhs: GoalWrapper) -> Bool {
        return lhs.goal.id == rhs.goal.id
    }

    public func hash(into hasher: inout Hasher) {
         hasher.combine(goal.id)
    }

    @Published var goal: Goal!
    let id: String
    init(goal: Goal) {
        self.goal = goal
        self.id = goal.id
   }
}

Is there some way How I can pass the updates to the list subviews? I have found some other people having issues with lists and passing a binding to the views in list. Is that the only way ?

Upvotes: 0

Views: 864

Answers (1)

George
George

Reputation: 30361

You don't need the GoalWrapper. You should pass goal as a Binding<Goal> from ContentView to GoalView.

If you get warnings where the ForEach is, you have the id property on Goal but may need to conform to the Identifiable protocol. Otherwise add the , id: \.id back.

Code:

struct ContentView: View {
    @ObservedObject var manager = AppConnectivityManager.shared

    var body: some View {
        List {
            ForEach($manager.goals) { $goal in
                let _ = print("goal in foreach: \(goal.completitionCount) + title: \(goal.title)")
                GoalView(goal: $goal)
            }.listRowBackground(Color.clear)
        }
    }
}
struct GoalView: View {
    @Binding var goal: Goal

    var body: some View {
        let _ = print("progress: \(goal.completitionCount) + daily: \(goal.dailyNotificationCount) + title: \(goal.title)")
        ZStack(content: {
            //GoalAnimationView(goalWrapper: self.goalWrapper).cornerRadius(10) // This needs changing too
            VStack(alignment: .leading, spacing: nil, content: {
                Text(goal.title).foregroundColor(.black).padding(.leading, 8)
                    .padding(.trailing, 8)
                    .padding(.top, 4)
                HStack(alignment: .center,content: {
                    Text("\(goal.completitionCount)/\(goal.dailyNotificationCount)").padding(.top, 2).padding(.trailing, 85).padding(.bottom, 6)
                    Text("\(goal.completitionCount)").padding(.top, 2).padding(.trailing, 12).padding(.bottom, 12).font(.title)
                }).frame(minWidth: 0, maxWidth: .infinity, minHeight: 0,maxHeight: 35,alignment: .trailing).background(Color.clear)


            }).listRowPlatterColor(Color.blue).frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, alignment: .leading).cornerRadius(10)

        })
    }
}

Upvotes: 1

Related Questions