Search code examples
xcodeswiftuiswiftui-listswiftui-navigationviewswiftui-form

Swiftui view not updating list after data append to array


I have three files: AddAssignment, ViewAssignment and Task. A button is clicked on AddAssignment.swift which successfully appends form data to an array inside of Task.swift.

However, in a file AddAssignment.swift, where each item in this array is passed through a loop, the view fails to update with the newly appended data.

AddAssignment.swift

import SwiftUI

struct AddAssignment: View {
    
    @State var taskName = ""
    @State var dueDate = ""
    @State var subject = ""
    @State var weighting = ""
    @State var totalMarks = ""
    @State var buttonClicked = false
    
    var body: some View {
        NavigationView {
            
            VStack {
                
                HStack { // Titling
                    Spacer()
                    Text("Add New Task")
                        .font(.headline)
                        .scaleEffect(2.0)
                    Spacer()
                    Image(systemName: "plus.square.fill")
                        .scaleEffect(2.0)
                    Spacer()
                }
                
                
                Form { // Gathering data
                    Section {
                        TextField("Enter task name",
                                  text: $taskName)
                        TextField("Enter due date",
                                  text: $dueDate)
                        TextField("Enter subject",
                                  text: $subject)
                    }
                    
                    Section(header: Text("Enter other task details:")) {
                        TextField("Enter task weighting",
                                  text: $weighting)
                        TextField("Enter total marks",
                                  text: $totalMarks)
                    }
                }
                
                if buttonClicked == true {
                    Text("Task Created")
                        .font(.subheadline)
                        .foregroundColor(.green)
                }
                
                Button(
                    action: {
                        data.append(Task(taskName: self.taskName,
                                         dueDate: self.dueDate,
                                         subject: self.subject,
                                         weighting: self.weighting,
                                         totalMarks: self.totalMarks))
                        buttonClicked = true
                    },
                    label: {
                        Text("Create New Task")
                            .frame(width: 250,
                                   height: 50,
                                   alignment: .center)
                            .background(Color.blue)
                            .foregroundColor(.white)
                            .cornerRadius(8)
                    })
                    .padding()
            }
        }
        
        
        
        
    }
    
}


struct AddAssignment_Previews: PreviewProvider {
    static var previews: some View {
        AddAssignment()
            .preferredColorScheme(.light)
    }
}

Task.swift (logic)

import SwiftUI

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

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"),
    ]

ViewAssignment.swift (where my error is occurring:)

import SwiftUI

struct ViewAssignment: View {
    var body: some View {
        NavigationView {
            List(data) { task in
                NavigationLink (
                    destination: TaskDetailView(),
                    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)
                        }
                    })
                
                
            }
            .navigationTitle("My Tasks")
            
        }
        
    }
}




struct ViewAssignment_Previews: PreviewProvider {
    static var previews: some View {
        ViewAssignment()
    }
}



Solution

  • 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"))
        }
    }