Adding alert to swipeable row iOS 15

Viewed 262

I have a list of views with the new swipeActions method from iOS 15 beta, when I try to add a confirmation dialog (alert) when the user swipes on a row, I am getting an error that says

"Closure containing control flow statement cannot be used with result builder 'TableRowBuilder'"

Here is the code that results in this error.

var body: some View {
        List {
            ForEach(itemStore.items, id: \.id) { item in
                if #available(iOS 15.0, *) {    // Error appears here
                    ItemView(item: item)
                        .swipeActions() {
                            Button {
                                withAnimation { showingAlert.toggle() }
                            } .alert("Important message", isPresented: $showingAlert) {
                                Button("First") { }
                                Button("Second") { }
                                Button("Third") { }
                            } label: {
                                Label("Delete", systemImage: "trash")
                            }
                        }
                        .tint(.red)
                } else {
                    // Fallback on earlier versions
                    ItemView(item: item)
                }
            }
        }
    }
1 Answers

The problem is here:

Button {
    withAnimation { showingAlert.toggle() }
} .alert("Important message", isPresented: $showingAlert) {
    Button("First") { }
    Button("Second") { }
    Button("Third") { }
} label: {
    Label("Delete", systemImage: "trash")
}

Button's initializer is actually init(action:label:), which looks like this:

Button {
    withAnimation { showingAlert.toggle() }
} label: {
    Label("Delete", systemImage: "trash")
}

You added an extra .alert in between the other parameters. This doesn't work. Instead, put the .alert outside the ForEach, for example on the List (it's best for alerts to be at the top level, not nested inside any subviews).

struct ItemStore {
    var items: [String]
}
struct ContentView: View {
    let itemStore = ItemStore(items: [
        "Hi",
        "Hello"
    ])
    @State var showingAlert = false
    
    var body: some View {
        List {
            ForEach(itemStore.items, id: \.self) { item in
                if #available(iOS 15.0, *) {
                    Text("Item: \(item)")
                        .swipeActions() {
                            Button {
                                withAnimation { showingAlert.toggle() }
                            } label: {
                                Label("Delete", systemImage: "trash")
                            }
                        }
                        .tint(.red)
                } else {
                    // Fallback on earlier versions
                    Text("Item: \(item)")
                }
            }
        } /// alert goes here!
        .alert("Important message", isPresented: $showingAlert) {
            Button("First") { }
            Button("Second") { }
            Button("Third") { }
        } 
    }
}
Related