Byto H
Byto H

Reputation: 73

How to persist data using MVVM in SwiftUI?

I’m practicing MVVM and SwiftUI by making a simple practice app. The main view of the app is a list where presents a title (in each cell) that can change by user input (text field). By selecting the cell, the app presents you the detail view where it presents another text.

I managed to change the cell´s title but I can’t figure out how to change the text in the detail view and make it stay that way. When I change the text in the detail view and go back to the main view, after entering again, the text doesn’t stay the same.

How can I make the text in the detail view maintain the text of whatever the user writes?

Upvotes: 0

Views: 452

Answers (2)

pawello2222
pawello2222

Reputation: 54516

Your Sandwish is a struct which means when you pass it around it's copied (See structure vs class in swift language). This also means that when you pass a sandwish:

CPCell(sandwish: sandwish)
...
struct CPCell: View {
    @State var sandwish: Sandwish
    ...
}

a sandwish is copied - any changes you make on this copy will not apply to the original sandwish.

When you do $sandwish.name in CPCell you're already binding to a copy. And in the NavigationLink you're copying it again.

struct CPCell: View {
    ...
    var body: some View {
        NavigationLink(destination: SandwishDetail(sandwish: sandwish)) {
            TextField("Record", text: $sandwish.name)
        }
    }
}

So in the SandwishDetail you're already using a copy of a copy of your original sandwish.

struct SandwishDetail: View {
    @State var sandwish: Sandwish // <- this is not the same struct as in `ContentView`
    ...
}

One way is to make Sandwish a class. Another, maybe better, solution is to use @Binding.

Note that the change from @State var sandwish to @Binding is not enough. CPCell expects the sandwish parameter to be Binding<Sandwish>, so you can't just pass a struct of type Sandwish.

One of the solutions is to use an index to access a binding from the SandwishStore:

ForEach (0..<store.sandwishes.count, id:\.self) { index in
    CPCell(sandwish: self.$store.sandwishes[index])
}
...
struct CPCell: View {
    @Binding var sandwish: Sandwish
    ...
}

Also you should do the same for all other places where the compiler expects Binding<Sandwish> and you originally passed Sandwish.

Upvotes: 2

Swift Enthusiast
Swift Enthusiast

Reputation: 63

Change @State to @Binding in Sandwish.swift and in your CPCell struct in ContentView.swift

Upvotes: 0

Related Questions