Reputation: 556
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
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