SwiftUI List content gets reset with selection

518 views Asked by At

Here is my issue: MainView displays ChildView and gives it an EnvironmentObject containing a set of selected items.

ChildView displays a list of selectable items(2 items in the example), and load the list when appearing.

The problem is that the ChildView content is reset to its original value (1 item in the example) when I tap on any row.

I tried to make my code as compact as possible.

struct MainView: View {
        
    @ObservedObject var model = MainViewModel()
    
    var body: some View {
        NavigationView {
            ChildView().environmentObject(self.model)
        }
    }
}

class MainViewModel: ObservableObject {
    
    @Published var selection = Set<Stuff>()
    
    var formatted: String {
        return "\(self.selection.count)"
    }
}

struct ChildView : View {
    
    @ObservedObject var cm = ChildViewModel()
    
    @EnvironmentObject var model: MainViewModel
    
    var body: some View {
        VStack(spacing: 0) {
            List(cm.demoData, id: \.self, selection: $model.selection) { stuff in
                Text("\(stuff.value)")
            }
            .environment(\.editMode, .constant(EditMode.active))
            .onAppear(perform: cm.load)
        }
    }
}

class ChildViewModel : ObservableObject {
    
    @Published var demoData: [Stuff] = [Stuff(id: 1, value: "1")]
    
    func load() {
        self.demoData = [Stuff(id: 1, value: "1"), Stuff(id: 2, value: "2")]
    }

}

struct Stuff : Identifiable, Equatable, Hashable {
    var id: Int
    var value: String
}

There is no problem if I don't use an environment object, but don't get how that causes the list to reset.

1

There are 1 answers

1
Asperi On BEST ANSWER

You modify MainViewModel and it cause rebuild body, including ChildView.

If you have iOS 14 as target minimal supported system the simplest solution is to use StateObject as it preserves view data

struct ChildView : View {
    
    @StateObject var cm = ChildViewModel()     // << here !!

    // ... other code