Detail View Is Not Updated When the Model Is Updated (Using List) Swiftui

Detail View is not updated when the model is updated (Using List) SwiftUI

This issue seems to be fixed in Xcode 13 Beta.

SwiftUI: Array Not Updating In All Views When Referencing The Same Observed Object

Ok I got it working. All I had to do was move the functions I had in my view to my viewModel. Im guessing to keep everything in the same scope. My guess is that everything in ContentView was it's own copy. I'm not 100% certain on that, but it works now.

ListView not updating after item class is modified in swiftui

try something simple like this, that works well for me:

@MainActor
class TasksViewModel: ObservableObject {

@Published var tasks = [Task]()

init() {
self.tasks = [Task(title: "TaskA", description: "DescriptionA"),
Task(title: "TaskB", description: "DescriptionB"),
Task(title: "TaskC", description: "DescriptionC"),
Task(title: "TaskD", description: "DescriptionD"),]
}

func randomTasks() {
tasks.forEach { task in
task.title = randomTitleTask()
task.description = randomDescriptionTask()
}
objectWillChange.send() // <--- here
}
}

struct TasksView: View {
@EnvironmentObject var viewModel: TasksViewModel
let timer = Timer.publish(every: 10, on: .main, in: .common).autoconnect()

var body: some View {
NavigationView {
List {
ForEach(viewModel.tasks, id: \.id) { task in
NavigationLink(destination: DetailView(task: task)) {
VStack {
Text(task.title)
Text(task.description)
}
}
}
}
.onReceive(timer) { time in
// no need for Task here since randomTasks is not an async
viewModel.randomTasks() // <--- here
}
}
}
}

Swiftui view not updating list after data append to array

You need to look at MVVM programming paradigm which is heavily used with SwiftUI.

So for your example you'd have your model:

struct Task: Identifiable {
var id: String = UUID().uuidString
var taskName: String
var dueDate: String
var subject: String
var weighting: String
var totalMarks: String
}

Your view:

struct ViewAssignment: View {

// Observed to update you UI
@ObservedObject var assignment = Assignments()

var body: some View {
NavigationView {
VStack {
List(self.assignment.data) { task in
NavigationLink (
destination: AdjustMe(),
label: {
Image(systemName: "doc.append.fill")
.scaleEffect(2.5)
.padding()

VStack(alignment: .leading, spacing: 3) {

Text(task.taskName)
.fontWeight(.semibold)
.lineLimit(2)

Text(task.dueDate)
.font(.subheadline)
.foregroundColor(.secondary)
}
})
}

// Alter your model by calling its functions
Button(action: {
self.assignment.addData()
}) {
Text("Add Data")
}
}

.navigationTitle("My Tasks")
}

}
}

And (important!) your class which wraps all the functions to alter your model.

// Must be ObservalbeObject
class Assignments: ObservableObject {
// Everything that gets adjusted and needs UI update has to be marked published
@Published var data: [Task] = [
Task(taskName: "Sample Task", dueDate: "1 Jan", subject: "Subject", weighting: "100", totalMarks: "100"),
Task(taskName: "Sample Task 2", dueDate: "2 Jan", subject: "Subject B", weighting: "100", totalMarks: "100"),
Task(taskName: "Sample Task 3", dueDate: "3 Jan", subject: "Subject C", weighting: "100", totalMarks: "100"),
]

// Function to alter your model/ view
func addData() {
self.data.append(Task(taskName: "Sample Task 4", dueDate: "5 Jan", subject: "Subject D", weighting: "200", totalMarks: "200"))
}
}

SwiftUI: .listRowBackground is not updated when new item added to the List

You can force the list to refresh when you cone back to the list. You can tag an id for your list by using .id(). Here is my solution:

struct ContentView: View {
@EnvironmentObject var vm: ViewModel
@State private var viewID = UUID()

var body: some View {
NavigationView {
List {
ForEach(vm.items, id: \.self) { item in
NavigationLink {
DetailView()
.environmentObject(vm)
} label: {
Text(item)
}
}
.listRowBackground(Color.yellow)
}
.id(viewID)
.onAppear {
viewID = UUID()
}
}
}
}

Hope it's helpful for you.

List item is not being updated

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)

})
}
}

SwiftUI List data update from destination view causes unexpected behaviour

You're controlling lifetimes and objects in a way that's not a pattern in this UI framework. The VieModel is not going to magically republish a singleton value type; it's going to instantiate with that value and then mutate its state without ever checking in with the shared instance again, unless it is rebuilt.

class Store: ObservableObject {
static var shared: Store = .init()

struct ContentView: View {
@ObservedObject var store = Store.shared
struct ItemDetailView: View {
@ObservedObject var viewModel = ItemDetailViewModel()

class ViewModel: ObservableObject {
@Published var items: [String] = Store.shared.items

There are lots of potential viable patterns. For example:

  1. Create class RootStore: ObservableObject and house it as an @StateObject in App. The lifetime of a StateObject is the lifetime of that view hierarchy's lifetime. You can expose it (a) directly to child views by .environmentObject(store) or (b) create a container object, such as Factory that vends ViewModels and pass that via the environment without exposing the store to views, or (c) do both a and b.

  2. If you reference the store in another class, hold a weak reference weak var store: Store?. If you keep state in that RootStore on @Published, then you can subscribe directly to that publisher or to the RootStore's own ObjectWillChangePublisher. You could also use other Combine publishers like CurrentValueSubject to achieve the same as @Published.

For code examples, see

Setting a StateObject value from child view causes NavigationView to pop all views

SwiftUI @Published Property Being Updated In DetailView



Related Topics



Leave a reply



Submit