iosswiftuicrashdata-storagenavigationsplitview

SwiftUI crashing when deleting item in NavigationSpiltView


I have a NavigationSplitView where I list items in data storage. If I delete the selected one (the one that is showing details in the "detail" part of the navigationsplitview, the app crashes. If I delete one that is not selected at the moment, there is no crash. For the deletion I use the .onDelete event in the List inside the NavigationSplitView.

var body: some View {
        @Bindable var nc = navigationContext
        NavigationSplitView {
//            let _ = print("Starting NavigationSplitView")
            List(selection: $nc.selectedTimeline) {
//                let _ = print("Starting List")
                ForEach(timelines){ timeline in
                    NavigationLink(timeline.name, value: timeline)
                }
                .onDelete(perform: removeTimelines)
            }
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
                ToolbarItem {
                    Button(action: {showNewTimeline = true}) {
                        Label("Add Timeline", systemImage: "plus")
                    }
                }
                ToolbarItem {
                    Button(action: {showEditTimeline = true}) {
                        Label("Edit Timeline", systemImage: "pencil")
                    }
                }
            }
        } detail: {
            TimelineView(timeline: nc.selectedTimeline)
                .environment(navigationContext)
        }
        .sheet(isPresented: $showNewTimeline) {
            TimelineEditorView(timeline: nil)
        }
        .sheet(isPresented: $showEditTimeline) {
            TimelineEditorView(timeline: navigationContext.selectedTimeline)
        }
    }
    
    func removeTimelines(at indexSet: IndexSet) {
        print("Deleting timelines...")
        for index in indexSet {
            let timelineToDelete = timelines[index]
            if navigationContext.selectedTimeline?.persistentModelID == timelineToDelete.persistentModelID {
               navigationContext.selectedTimeline = nil
            }
            modelContext.delete(timelineToDelete)
        }
    }

The error is this: *** Assertion failure in -[SwiftUI.UpdateCoalescingCollectionView validateSelectionOrHighlightIndexPath:isSelection:allowMassIndexPath:assertIfInvalid:], UICollectionView.m:8266 Attempted to modify the selection of an out-of-bounds item (1) when there are only 1 items in section 0. Collection view: <SwiftUI.UpdateCoalescingCollectionView: 0x13480e600; baseClass = UICollectionView; frame = (0 0; 420 998); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x600001898390>; backgroundColor = UIExtendedGrayColorSpace 0 0; layer = <CALayer: 0x6000016949c0>; contentOffset: {0, -70}; contentSize: {420, 54}; adjustedContentInset: {70, 0, 0, 0}; layout: <UICollectionViewCompositionalLayout: 0x133e15090>; dataSource: <TtGC7SwiftUI31UICollectionViewListCoordinatorGVS_28CollectionViewListDataSourceC12Timeline_iOS8Timeline_GOS_19SelectionManagerBoxS3_: 0x135870160>>.


Solution

  • You are trying to deselect an item that no longer exists, causing the crash.

    Change your removeTimelines function to

    func removeTimelines(at indexSet: IndexSet) {
        print("Deleting timelines...")
        for index in indexSet {
            let timelineToDelete = timelines[index]
            modelContext.delete(timelineToDelete)
        }
    }