[SOLVED] My published variables in my view Model get reset to their default values when i run the code

Issue

This Content is from Stack Overflow. Question asked by Emere

I have been having problems with updating a published variable in my model, so I tried to replicate the problem with a very basic and simple set of files/codes. So basically in NavLink view, there is a navigation link, which when clicked, it updates the published variable in ListRepository model by giving it a string value of “yes”, prints it to the console then navigates to its destination which is called ContentView view. The problem is in ContentView, I tried to print the data contained in the published variable called selectedFolderId hoping it will print “yes”, but i noticed that instead of printing the value that was set in NavLink view, it instead printed the default value of "", which was not what was set in NavLink view. Please can anyone explain the reason for this behaviour and explain to me how it can fix this as i am very new in swift ui. That will mean alot.

Please find the supporting files below:

import SwiftUI

struct NavLink: View {

    @ObservedObject var listRepository = ListRepository()
    
    var body: some View {
        
        NavigationView{
            ScrollView {
                
                NavigationLink("Hello world", destination: ContentView())
                
                Text("Player 1")
                Text("Player 2")
                Text("Player 3")
            }
            .simultaneousGesture(TapGesture().onEnded{
                listRepository.selectedFolderId = "yes"
                listRepository.md()
            })
            .navigationTitle("Players")
        }
    }
}

struct NavLink_Previews: PreviewProvider {
    static var previews: some View {
        NavLink()
    }
}
import Foundation


class ListRepository: ObservableObject {
    
    @Published var selectedFolderId = ""
    
    func md(){
        print("=====")
        print(self.selectedFolderId)
        print("======")
    }
}
import SwiftUI

struct ContentView: View {
    
    @ObservedObject var listRepository = ListRepository()
    
    var body: some View {
        VStack{
            Text("content 1")
            Text("content 2")
            Text("content 3")
        }
        .onAppear{
            print("========")
            print(listRepository.selectedFolderId)
            print("========")
            
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}



Solution

This is a common issue when you first deal with data flow in an app. The problem is straightforward. In your ‘NavLink’ view you are creating one version of ListRepository, and in ContentView you create a separate and different version of ListRepository. What you need to do is pass the ListRepository created in NavLink into ContentView when you call it. Here is one example as to how:

struct NavLink: View {

    @StateObject var listRepository = ListRepository() // Create as StateObject, not ObservedObject
    
    var body: some View {
        
        NavigationView{
            ScrollView {
                
                NavigationLink("Hello world", destination: ContentView(listRepository: listRepository)) // Pass it here
                
                Text("Player 1")
                Text("Player 2")
                Text("Player 3")
            }
            .simultaneousGesture(TapGesture().onEnded{
                listRepository.selectedFolderId = "yes"
                listRepository.md()
            })
            .navigationTitle("Players")
        }
    }
}

struct ContentView: View {

    @ObservedObject var listRepository: ListRepository // Do not create it here, just receive it
    
    var body: some View {
        VStack{
            Text("content 1")
            Text("content 2")
            Text("content 3")
        }
        .onAppear{
            print("========")
            print(listRepository.selectedFolderId)
            print("========")
            
        }
    }
}

You should also notice that I created ListRepository as a StateObject. The view that originally creates an ObservableObject must create it as a StateObject or you can get undesirable side effects.


This Question was asked in StackOverflow by Emere and Answered by Yrb It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

people found this article helpful. What about you?