iosswiftui

Textfield inside alert not working on iPhone, but fine on iPad (SwiftUI)


I have a simple List within a NavigationStack. I placed a button at the bottom of the list to add an item to the array that populate the list.

The button triggers an alert with a Textfield in it to provide the name for the new item.

This works flawlessly on my iPad, on previews using both iPad and iPhone, and on Simulator also using both iPad and iPhone.

However, the TextField somehow does not work properly in my actual iPhone (running 18.5 - maybe that's the issue? Though I am also using 18.5 on iPad).

It doesn't work this way: when I press the "+ ingredient" button, the alert appears correctly. I am able to enter text in it. But after pressing the "Add" button on alert dialog the closure doesn't run (I put breakpoints inside closure, and they are never reached).

Thanks in advance for any ideas.

(If I take the TextField out, and have the Add button within the alert just add an ingredient to the array, that works fine.)

Here's the code

import SwiftUI

struct IngredientsEditView: View {
    
    @AppStorage("ingredients") var ingredients = starterIngredients
    @AppStorage("ingredientsDone") var ingredientsDone: Bool = false
    @State private var addingIngredient = false
    @State private var newIngredient = ""
    
    var body: some View {
        NavigationStack {
            List {
                Section {
                    ForEach ($ingredients, id: \.self, editActions: .all) { $ingredient in
                        Text(ingredient)
                    }
                    .onDelete(perform: delete)
                    .onMove(perform: move)
                } 
                Button("+ ingredient") {
                    addingIngredient.toggle()
                }
                .alert("New Ingredient", isPresented: $addingIngredient) {
                    TextField("Ingredient", text: $newIngredient)
                    Button("Cancel", role: .cancel) {
                        newIngredient = ""
                    }
                    Button("Add") {
                        if !newIngredient.isEmpty {
                            ingredients.append(newIngredient)
                            newIngredient = ""
                        }
                    }
                }
            }
            .navigationTitle("Ingredients")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("Start Ordering!") {
                        ingredientsDone = true
                    }
                }
            }
        }
    }
    
    func delete(indexSet: IndexSet) {
        ingredients.remove(atOffsets: indexSet)
    }
    
    func move(from source: IndexSet, to destination: Int) {
        ingredients.move(fromOffsets: source, toOffset: destination)
    }
}


#Preview {
    IngredientsEditView()
}

Solution

  • Move the .alert(...) outside the List or even outside the NavigationStack.

    Note also the comment of not using id: \.self in the ForEach. Similarly, @AppStorage is not the appropriate store for an array of ingredients