简体   繁体   中英

SwiftUI: Update views when conditions / ObservableObject changed while view is opened

I guess it is mostlikely a stupid question, but currently I am struggling. To avoid tons of code, I simplified the code (see below) but it should show the problem.

I've got multiple views that are not in a parental relationship. On one view (ViewA) I set a target date. On another view (ViewB) I show text, depending on the fact whether the target date is in future or not. For both views I am using a ObservableObject. I would like to have that ViewB changes the text when it is open and the target date is reached at that time. Since I am using the tag @Published, I was expecting it works directly. But unfortunately, nothing happens.

This is my initial approach.

I tested some more solutions, eg

  1. polling by a timer in the views with a function to get the current date
  2. I also thought about first calculating the remaining time and a timer in another thread within the ObservedObject that fires an event when the timer reaches 0 and onReceive modifiers in the views.

But I guess my approach(es) is (are) very bad I there will be a way better solution.

Your help is really appreciated.

Thanks, Sebastian


SearchData:

class SearchData: ObservableObject {

   @Published var targetDate: Date = UserDefaults.standard.object(forKey: "targetDate") as? Date ?? Date() {
       didSet {
           UserDefaults.standard.set(self.targetDate, forKey: "targetDate")
       }
   }
}


View A:

struct ViewA: View {
   @ObservedObject var searchData = SearchData()

   func setDate() {
       searchData.targetDate = Date() + 120
   }

   var body: some View {

       Button(action: {
           self.setDate()
       }) {
           Text("Set Date")
       }
   }
}


View B:

struct ViewB: View {
   @ObservedObject var searchData = SearchData()

   var body: some View {
       VStack() {
           if searchData.targetDate > Date() {
               Text("Text A")
           } else {
               Text("Text B")
           }
           Spacer()
           Text("\(searchData.targetDate)")
       }
       .padding()
   }
}

The ViewA and ViewB use different instances of SearchData . To make published work directly, as you wrote, both views have to use one instance of observable object.

struct ViewA: View {
   @ObservedObject var searchData: SearchData
   /// ... other code

struct ViewB: View {
   @ObservedObject var searchData: SearchData
   /// ... other code

and somewhere you crate them

let searchData = SearchData()
...

ViewA(searchData: searchData)

...

ViewB(searchData: searchData)

If ViewA and ViewB live in different view hierarchies then probably would be more appropriate to use @EnvironmentObject

struct ViewA: View {
   @EnvironmentObject var searchData: SearchData
   /// ... other code

struct ViewB: View {
   @EnvironmentObject var searchData: SearchData
   /// ... other code

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM