Home > OS >  Why does View with ObservedObject in it, repeat multiple times when I have an active timer running
Why does View with ObservedObject in it, repeat multiple times when I have an active timer running

Time:03-15

I have a @Published Date() variable that I want to update every 5 seconds to keep app time in sync.\

I tired placing the timer inside the class, but that does not revolve the issue either.

video preview videolink (YouTube)

import SwiftUI

struct ContentView: View {
    @State var countdown = Timer.publish(every: 2, on: .current, in: .default).autoconnect()
    
    @ObservedObject var timer = globalTime()
    var body: some View {
        
        
        VStack{
            Text("time \(timer.currentDate)")
            Text("This is a view")
            
        }
        .toolbar(content: {
            
            ToolbarItem(id: "help",placement: .navigationBarLeading) {
                NavigationLink(
                    destination: ContentView2(),
                    label: {
                        Text("View Link")
                    })
            }
        })
        .onReceive(countdown, perform: { _ in
            timer.currentDate = timer.currentDate.addingTimeInterval(2)
            
        
        })
        
    }
}

class globalTime: ObservableObject { 
    @Published var currentDate = Date(timeIntervalSince1970: 12)   
}
//NavigationLink View

struct ContentView2: View {
    @ObservedObject var global = globalTime() 
    var body: some View {
        
        VStack{
            Text("This is a view")    
        }
    }  
}

CodePudding user response:

For starters, you have a Publisher stored as a @State variable, which you shouldn't be doing. That timer is never modified and should be a let property, or bound to a Published variable, on your ObservableObject. Second, in ContentView2 you have an observable object being set from inside the same view but ObservableObject means that that object's storage is handled externally, so by assigning the value where it's declared, you're violating the observable object contract. If you want to declare it inside your view, use @StateObject; ObservableObject is used when you pass view models down to children views. In that case, the parent is responsible for the view models storage so that when the child reloads, it doesn't also reload the view model.

I ran your code and I am not getting multiple navigation link pushes like your video shows. If you're still experiencing the issue, try a couple things:

  • define your timer publisher on the observable object
  • change @ObservableObject to @StateObject

CodePudding user response:

there are a number of issues with your code. You need a NavigationView to be able to use a NavigationLink. Also you need to pass the timer to your next View ContentView2 for it to be available in that view. The following code shows some of these concepts.

struct ContentView: View {
    let countdown = Timer.publish(every: 2, on: .current, in: .default).autoconnect()
    
    @StateObject var timer = globalTime() // <-- here
    
    var body: some View {
        NavigationView {
            VStack{
                Text("time \(timer.currentDate)")
            }
            .toolbar {
                ToolbarItem(id: "help", placement: .navigationBarLeading) {
                    NavigationLink(destination: ContentView2(global: timer)) {
                        Text("View Link")
                    }
                }
            }
            .onReceive(countdown) { _ in
                timer.currentDate = timer.currentDate.addingTimeInterval(2)
            }
        }
    }
}

class globalTime: ObservableObject {
    @Published var currentDate = Date(timeIntervalSince1970: 12)
}

struct ContentView2: View {
    @ObservedObject var global: globalTime  // <-- here
    
    var body: some View {
        VStack{
            Text("This is a view")
            Text("time \(global.currentDate)")  // <-- here
        }
    }
}
  • Related