Home > Mobile >  Finding an item in an array and updating its value
Finding an item in an array and updating its value

Time:10-05

I have a DataModel with the following struct:

struct Task: Codable, Hashable, Identifiable {
    var id = UUID()
    var title: String
    var completed = false
    var priority = 2
}

In one my views, I populate a list with buttons based on each element of that DataModel, essentially a Task.

I pass each task for the view like this:

ForEach(taskdata.filteredTasks(byPriority: byPriotity), id: \.id) { task in
           TaskView(task: task)
}

On the view, I add each button as follow:

struct TaskView: View {
    @EnvironmentObject private var taskdata: DataModel
    @State var task: Task
    
    var body: some View {
        Button(action: {
            task.completed.toggle() }) {
         
            ....
         }
    }
}

Now, when the user clicks on the button, if completed was false, it makes it true. Simple. However, this doesn't update the DataModel, so I added the following to see if I could find the item in question and update it:

struct TaskView: View {
    @EnvironmentObject private var taskdata: DataModel
    @State var task: Task
    @State var id: UUID // added this so I can also pass the ID and try to find it
    
    var body: some View {
        Button(action: {
            task.completed.toggle()
            if task.completed { // if it's completed, find it an update it.
                //taskdata.tasks.first(where: { $0.id == id })?.completed = true
                //taskdata.tasks.filter {$0.id == id}.first?.completed = true
                
                /*if let index = taskdata.tasks.first(where: {$0.id == id}) {
                    print(index)
                    taskdata.tasks ????
                }*/
            }
        }) {
             ....
           }

All the commented code is what I have tried... I get different errors, from Cannot assign to property: function call returns immutable value to cannot assign to property: 'first' is a get-only property and a few other colorful Xcode errors.

How do I find the correct object on my DataModel and correctly update its .completed to true (or false if it's clicked again).

Thank you

CodePudding user response:

You need to use Array >>> firstIndex

if let index = taskdata.tasks.firstIndex(where: {$0.id == id}) { 
  taskdata.tasks[index].completed = true
}

CodePudding user response:

There is another way for your problem using a function in extension like this custom update function:

extension Array {

    mutating func update(where condition: (Element) -> Bool, with newElement: (Element) -> Element) {
        
        if let unwrappedIndex: Int = self.firstIndex(where: { value in condition(value) }) {
            
            self[unwrappedIndex] = newElement(self[unwrappedIndex])
            
        }
  
    }
    
}

use case:

taskdata.tasks.update(where: { element in element.id == id }, with: { element in
    
    var newElement: Task = element
    
    newElement.completed = true
    
    return newElement
 
})
  • Related