Why is "toggle()" function not producing the same result as explicitly writing out a toggle?

34 views Asked by At

The following block works:

Main File

import SwiftUI

struct Home: View {
    @State private var ToDoItems: [ToDoItem] = [ToDoItem(title: "Task", description: "Need to do", urgent: false)]
    @State private var isAddingToDo: Bool = false
    
    var body: some View {
        VStack {
            
            ScrollView {
                ForEach(ToDoItems.indices, id: \.self) { index in
                    
                    HStack {
                        
                        Button {
                            if ToDoItems[index].done {
                                ToDoItems[index].done = false
                            } else {
                                ToDoItems[index].done = true
                            }
                        } label: {
                            if ToDoItems[index].done {
                                Image(systemName: "square.fill")
                            } else {
                                Image(systemName: "square")
                            }
                        }
                        
                        Text(ToDoItems[index].title)
                            .font(.title)
                    
                        
                    }
                    .padding()
                    
                }   
            }
            
        }

ToDoItem Declaration

import SwiftUI

struct ToDoItem: Identifiable {
    var title: String
    var createdAt: NSDate = NSDate()
    var id = UUID()
    var description: String
    var done = false
    var urgent: Bool
    init(title: String, description: String, done: Bool = false, urgent: Bool) {
        self.title = title
        self.description = description
        self.done = done
        self.urgent = urgent
    }
}

The "done" property on the ToDoItem struct is a boolean that defaults to false.

I could not get the view to update when I switched the block

Button {
    if ToDoItems[index].done {
        ToDoItems[index].done = false
    } else {
        ToDoItems[index].done = true
                            }
} label: {
    if ToDoItems[index].done {
        Image(systemName: "square.fill")
    } else {
        Image(systemName: "square")
    }
}

with the block

Button {
    ToDoItems[index].done.toggle()
} label: {
    if ToDoItems[index].done {
        Image(systemName: "square.fill")
    } else {
        Image(systemName: "square")
    }
}

Why is this? Do I have a misunderstanding of the toggle function? Shouldn't it update the done property the same way my block of code does?

UPDATE: In the ToDoItem Declaration I added the Bool type declaration and it works now.

Updated ToDoItem Declaration

import SwiftUI

struct ToDoItem: Identifiable {
    var title: String
    var createdAt: NSDate = NSDate()
    var id = UUID()
    var description: String
    var done: Bool = false  ***Updated line
    var urgent: Bool
    init(title: String, description: String, done: Bool = false, urgent: Bool) {
        self.title = title
        self.description = description
        self.done = done
        self.urgent = urgent
    }
}
1

There are 1 answers

0
cbear84 On

If I understand what you're asking correctly, you are initializing a default on the Model (ToDoItem). Below keeps the Model free of any state.

struct ToDoItem: Identifiable {
    var title: String
    let createdAt = NSDate()
    let id = UUID()
    var description: String
    var done: Bool
    var urgent: Bool

}

You are initializing the data here. You can hard code the initial state in the test data to set the data.

@State private var ToDoItems: [ToDoItem] = [
    ToDoItem(title: "Task", description: "Need to do", done: false, urgent: false),
    ToDoItem(title: "More", description: "Need more to do", done: true, urgent: false)
]

@State private var isAddingToDo: Bool = false

    var body: some View {
    VStack {
        
        ScrollView {
            ForEach(ToDoItems.indices, id: \.self) { index in
                HStack {
                    Button {
                        ToDoItems[index].done.toggle()
                    } label: {
                        HStack {
                            Image(systemName: ToDoItems[index].done == true ? "square.fill" : "square")
                            Text(ToDoItems[index].title)
                                .font(.title)
                        }
                    }
                    .padding()
                }
            }
        }
    }
}

}