Search code examples
swiftuiios15xcode13

SwiftUI .swipeactions and Core Data


Currently using Xcode 13 and IOS 15.

I am using CoreData to display a list of upcoming trips. On each trip I have 2 swipe actions, one to delete the trip, and the second one is to edit the trip. When the Edit button is selected I then trigger the showingEditTripScreen to true so that the EditTripScreen sheet is shown. I am passing the trip into this sheet to be edited. The problem is that no matter what Trip from the ForEach row is selected, it is always the first trip data that is being sent to the EditTripScreen. Am I doing this properly, or is their another solution. Thanks

ForEach(tripVM.trips, id: \.id) { trip in
                            TripCardView(trip: trip)
                                .listRowSeparator(.hidden)
                                //.padding(.horizontal)
                            
                                .swipeActions(allowsFullSwipe: false) {
                                            // Edit Trip
                                            Button {
                                               showingEditTripScreen = true
                                                
                                            } label: {
                                                
                                                Label("Edit", systemImage: "pencil.circle.fill")
                                                    
                                            }
                                            
                                            .tint(.green)
                                            
                                            // Delete Trip
                                            Button {
                                                tripVM.deleteTrip(trip: trip)
                                                tripVM.getAllTrips()
                                              
                                            } label: {
                                                Label("Delete", systemImage: "trash.circle.fill")
                                                    
                                            }
                                            .tint(.red)
                                        }
                                .sheet(isPresented: $showingEditTripScreen, onDismiss: {
                                    
                                }, content: {
                                    
                                    EditTripScreen(trip: trip)
                                })
    
                        }

Solution

  • You're adding sheet for each cell of your table. So when you set showingEditTripScreen variable to true, all sheets for visible views gets triggered, and only one of them will be shown, maybe the first one or just a random one.

    Instead you need to store selected trip and use sheet(item:onDismiss:content:), which will pass you unwrapped item to your content. And this sheet should be single one for your list, not need to add it to each item.

    Also onDismiss is an optional parameter, you don't need to pass it if you're not using it. editingTrip will be set to nil when you dismiss it automatically.

    @State
    var editingTrip: Trip?
    
    var body: some View {
        ForEach(tripVM.trips, id: \.id) { trip in
            TripCardView(trip: trip)
                .listRowSeparator(.hidden)
                //.padding(.horizontal)
                
                .swipeActions(allowsFullSwipe: false) {
                    // Edit Trip
                    Button {
                        editingTrip = trip
                    } label: {
                        
                        Label("Edit", systemImage: "pencil.circle.fill")
                        
                    }
                    
                    .tint(.green)
                    
                    // Delete Trip
                    Button {
                        tripVM.deleteTrip(trip: trip)
                        tripVM.getAllTrips()
                        
                    } label: {
                        Label("Delete", systemImage: "trash.circle.fill")
                        
                    }
                    .tint(.red)
                }
            
        }
        .sheet(item: $editingTrip, content: { editingTrip in
            EditTripScreen(trip: editingTrip)
        })
    }