2

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()
    }
}


3
  • Please do not declare data as a global variable. Create an observable view model. Commented Jul 26, 2021 at 9:28
  • How would I go about doing this without creating a new instance every time the view is opened, since all of these views are controlled by tab views? Commented Jul 26, 2021 at 9:30
  • You could make it an Environment variable Commented Jul 26, 2021 at 10:34

1 Answer 1

0

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"))
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Hi, thanks for the response. I am kind of familiar with using ObservableObject, but would I be able to use this method in the AddAssignment view, so that when the button is clicked, a new list item is created based on what is entered into the text field?
You can access the object anywhere you declare it or send it to. If this model is used throughout your app make it an environment object. Like that you can call the same instance from everywhere and dont need to pass it around. Like so on ContentView().environmentObject(YourClass())
Ahh good idea. I attached an environmentObject attribute to my ContentView file which was a tab view for all my screens, and so I was able to use the same instance across all menus. Thank you so much for the help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.