SwiftUI List cells not displaying selection state correctly after scrolling

Viewed 714

EDIT: It happens on iOS 14.2 - 14.5, but not 14.1 or 14.0. It's a SwiftUI regression. I don't know a workaround so far.


I'm having issues with the SwiftUI List selection, when the user scrolls. Selected cells that get scrolled offscreen and then become visible again are not displayed as selected.

SwiftUI List Selection issue

Am I missing something or is this a SwiftUI bug?

It seems like the internal SwiftUI List coordinator is using UITableView and doesn't correctly update the cell state for the selection state.

struct Item: Identifiable, Hashable {
    let id: Int
}

class ViewModel: ObservableObject {
  @Published var selectedItems: Set<Int>
  @Published var items: Array<Item>
  
  init() {
    self.items = [Item(id: 1), Item(id: 2), Item(id: 3), Item(id: 4), Item(id: 5),
                  Item(id: 6), Item(id: 7), Item(id: 8), Item(id: 9), Item(id: 10),
                  Item(id: 11), Item(id: 12), Item(id: 13), Item(id: 14), Item(id: 15),]
    self.selectedItems = []
  }
}

struct ContentView: View {
    
    @ObservedObject var context: ViewModel
     
    var body: some View {
//        Alternative also doesn't work.
//        List(context.items, id: \.id, selection: $context.selectedItems) { item in
//            Text("\(item.id)").id(item.id)
//        }
//        .environment(\.editMode, .constant(.active))
        
        List(context.items, selection: $context.selectedItems) { item in
            Text("\(item.id)")
        }
        .environment(\.editMode, .constant(.active))
        
    }
}

The console output:

ListSelection[6659:3960182] [Assert] Attempted to call -cellForRowAtIndexPath: on the table view while it was in the process of updating its visible cells, which is not allowed. Make a symbolic breakpoint at UITableViewAlertForCellForRowAtIndexPathAccessDuringUpdate to catch this in the debugger and see what caused this to occur. Perhaps you are trying to ask the table view for a cell from inside a table view callback about a specific row? Table view: <TtC7SwiftUIP33_BFB370BA5F1BADDC9D83021565761A4925UpdateCoalescingTableView: 0x10381ec00; baseClass = UITableView; ...; dataSource: <TtGC7SwiftUIP10$1b198497819ListCoreCoordinatorGVS_20SystemListDataSourceSi_GOS_19SelectionManagerBoxSi: 0x10340a930>>

1 Answers

This seems to be a Swift bug on 14.2-14.3 because my app had the selections working normally but now it's facing these exact same visual issues as described.

Related