0
votes

I'm a new SwiftUi developer, and I'm loving it. I've tried some stuff and I'm now facing a weird behaviour of my code, more specifically concerning the UI update.

My View - ViewModel Code

class UUIDViewModel : ObservableObject {
    var timer: Timer?
    @Published var i = 0
    @Published var text = UUID.init().uuidString
    
    func generateUUID() -> Void {
        self.i = 0
        self.timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { (timer) in
            print(self.i)
            self.text = UUID.init().uuidString
            if self.i == 5 {
                self.timer?.invalidate()
            }
            self.i = self.i + 1
        }
    }
}

struct FirstView: View {
    
    @ObservedObject var uuidVm = UUIDViewModel()
    @EnvironmentObject var tabBarVM: TabBarViewModel
    
    var body: some View {
        VStack {
            Button("start", action:  { 
                tabBarVM.hasNotification = true
                uuidVm.generateUUID()
            })
            Text(uuidVm.text)
                .padding()
                .font(.system(size: 30, weight: .bold, design: .rounded))
        }

    }
}

struct FirstView_Previews: PreviewProvider {
    static var previews: some View {
        FirstView()
    }
}

And here the main View with the TabBar, The goal here is to update a tabBar item text when we click the start Button of another view.

When there is no injection of the TabBarViewModel, the ui is well updated 5 times with new uuid. But when I inject the ViewModel, the timer is started, the text inside the tabBar as well, but the UI inside the FirstView is not updated anymore when the timer repeat.

Am I missing something ? Thanks !


class TabBarViewModel : ObservableObject {
    @Published var hasNotification = false

}

struct ContentView: View {
    
    @ObservedObject var tabBarVM = TabBarViewModel()
    @State private var selection = 0
    
    init() {
        UITabBar.appearance().barTintColor = .white
    }
    
    var body: some View {
        TabView(selection: $selection,
                content: {
                    FirstView()
                        .tabItem {
                            Image(systemName: "house.fill")
                            Text(tabBarVM.hasNotification ? "Notif" : "Home")
                        }.environmentObject(tabBarVM)

                    Text("Bookmark Tab")
                        .font(.system(size: 30, weight: .bold, design: .rounded))
                        .tabItem {
                            Image(systemName: "bookmark.circle.fill")
                            Text("Bookmark")
                        }

                    Text("Video Tab")
                        .font(.system(size: 30, weight: .bold, design: .rounded))
                        .tabItem {
                            Image(systemName: "video.circle.fill")
                            Text("Video")
                        }

                    Text("Profile Tab")
                        .font(.system(size: 30, weight: .bold, design: .rounded))
                        .tabItem {
                            Image(systemName: "person.crop.circle")
                            Text("Profile")
                        }
                })
    }
}

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

1 Answers

0
votes

Change ObservedObject to StateObject.

struct FirstView: View {
    
    @StateObject var uuidVm = UUIDViewModel() //<--Here
    @EnvironmentObject var tabBarVM: TabBarViewModel

   //Other body code 
}

Another way is to remove @ObservedObject from the tabBar view, no need @ObservedObject.

struct ContentView: View {
    
    var tabBarVM = TabBarViewModel() //<-- Here
    
    //Other code
}