SwiftUI macOS Table refresh not keeping selection

On macOS tables if refreshing occasionally for example refresh data every second,

  • If you will try to select a row at the point the table refreshes the selection is lost
  • If you will try to mouse down on a row, you will see the row selected but when the table refreshes, the selection is lost

Notes: I filled a bug already.

Wonder if there is any workaround for that.

Sample code to reproduce:


import SwiftUI

struct TableItem: Identifiable {
    var id: String {
        name
    }
    var name: String
    var counter: Int
}

@Observable
class TableViewModel {
    var items: [TableItem] = [
        .init(name: "Row 1", counter: 10),
        .init(name: "Row 2", counter: 0),
        .init(name: "Row 3", counter: 56),
        .init(name: "Row 4", counter: 7)
    ]

    var selection: Set<TableItem.ID> = []

    func incrementCounters() {
        for index in items.indices {
            items[index].counter += 1
        }
    }
}

struct ContentView: View {
    @Bindable var viewModel = TableViewModel()
    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

    var body: some View {
        VStack {
            Table(viewModel.items, selection: $viewModel.selection) {
                TableColumn("name") { item in
                    Text(item.name)
                }
                .width(min: 80, ideal: 150)

                TableColumn("counter") { item in
                    Text("\(item.counter)")
                }
                .width(min: 80, ideal: 150)
            }
        }
        .padding()
        .onReceive(timer) { input in
            viewModel.incrementCounters()
        }
    }
}

Why @Bindable for the viewModel? Since you are using the Observation framework, make the viewModel @State var viewModel = TableViewModel (this is if you want to initialize the viewModel elsewhere and pass it in. Otherwise use @State private var viewModel = TableViewModel()

The reason why it isn't keeping the selection is because your view is probably redrawn and the viewModel is reinitialized, on initialization you set selections to []

You didn't understand the bug. The deselection occurs when trying to select a row at the same time as the table reloads. Run the above code on a macOS app project and try to select rows. You will see what is going wrong

SwiftUI macOS Table refresh not keeping selection
 
 
Q