Search code examples
swiftswiftuistatestate-management

SwiftUI Bool state not updated or incorrect


Working with Xcode 15 on the latest available version of macOS 14, I have a very simple SwiftUI form whose Save button is supposed to be disabled only as long as both of the form fields are filled in:

import SwiftUI
import SwiftData

struct AddToDoScreen: View {
    @Environment(\.dismiss) private var dismiss
    @Environment(\.modelContext) private var context
    
    @State private var name: String = ""
    @State private var priority: Int?
    
    private var isFormValid: Bool {
        !name.isEmpty && priority != nil
    }
    
    var body: some View {
        Form {
            TextField("Name", text: $name)
            TextField("Priority", value: $priority, format: .number)
        }
        .navigationTitle("Add ToDo")
        .toolbar {
            ToolbarItem(placement: .topBarLeading) {
                Button("Dismiss") {
                    dismiss()
                }
            }
            
            ToolbarItem(placement: .topBarTrailing) {
                Button("Save") {
                    
                    guard let priority = priority else { return }
                    
                    let toDo = ToDo(name: name, priority: priority)
                    context.insert(toDo)
                    
                    do {
                        try context.save()
                    } catch {
                        print(error.localizedDescription)
                    }
                    
                    dismiss()
                    
                }.disabled(!isFormValid)
            }
        }
    }
}

Screenshot

GitHub link of the project: https://github.com/atilsamancioglu/iOS50-SwiftDataToDo

Is there anything wrong with my code or is this another Apple bug? Is there anything I can do as a fix or workaround?


Solution

  • You need to type in a number in the second text field since you used format: .number. If it can't parse the text as a number then it sets your Int? state to nil and thats why the button does not enable.

    FYI I looked at your project and it's best if you switch from sheet(isPresented:) to sheet(item:). In the button action create the new model object, store it as an @State var item that you use as the sheet's binding. Then in the AddToDoScreen bind your text fields to that object instead of those independent states.