0

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)
                                })
    
                        }
diver91
  • 27
  • 5

1 Answers1

0

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)
    })
}
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
  • Thanks for the response. I tried this and I am getting errors on the sheet: Cannot convert value of type 'Binding' to expected argument type 'Binding', Referencing static method 'buildBlock' on 'Optional' requires that 'Trip' conform to 'View', and Cannot convert value of type 'Trip?' to expected argument type 'TripViewModel' – diver91 Aug 29 '21 at 00:23
  • @diver91 I made a typo, see updated answer – Phil Dukhov Aug 29 '21 at 03:48
  • Thanks, but I am still getting errors on the sheet. I uploaded my project to GitHub if you wanted to try it out on my full project: [link(https://github.com/diver91/Travelogue) – diver91 Aug 29 '21 at 17:35
  • @diver91 what exact errors are you getting? This project is huge, I don't wanna download it and build. – Phil Dukhov Aug 29 '21 at 18:18
  • Same errors as before on the sheet. Here is a screenshot of those errors: https://www.icloud.com/iclouddrive/0gTi7ySjTRc0cZ9R8Gjnqe__Q#Screen_Shot_2021-08-29_at_3.01.38_PM – diver91 Aug 29 '21 at 20:03
  • @diver91 you didn't follow my update with a typo, replace `isPresented` with `item`. Also make sure it is outside `ForEach`, it is not clear from the screenshot if it is there. – Phil Dukhov Aug 30 '21 at 02:37
  • Thanks I missed the update. It is outside of the ForEach. Will try it once I get power back on from Hurricane Ida. Might be a week or 2. – diver91 Aug 30 '21 at 21:09
  • @diver91 Wow, that's tough, hang on in there. – Phil Dukhov Aug 31 '21 at 04:59
  • Thanks! It works with this: `.sheet(item: $editingTrip, content: { editingTrip in EditTripScreen(trip: editingTrip) })` Just had to add `in` and everything is working now. – diver91 Sep 10 '21 at 13:24