My4Paws
My4Paws

Reputation: 51

How to re-trigger function whenever a variable is updated

UPDATED

I'm pulling events from IOS calendar with EventKit. Working great.

Here's the class function that retrieves the events.

@ObservedObject var selectDate = datepicker() // does NOT update as expected.
func loadEvents(completion: @escaping (([EKEvent]?) -> Void)) {
    requestAccess(onGranted: {
        let startOfDay = Calendar.current.startOfDay(for: self.selectDate.selectedDate)
        let endOfDay = Calendar.current.startOfDay(for: self.selectDate.selectedDate.advanced(by: TimeInterval.day))
        let predicate = self.eventStore.predicateForEvents(withStart: startOfDay, end: endOfDay, calendars: Array(self.selectedCalendars ?? []))
        let events = self.eventStore.events(matching: predicate)

        completion(events)
        print("loadEvents triggered for \(self.selectDate.selectedDate)") // This ALWAYS returns the current date
    }) {
        completion(nil)
    }
}

I want to update the results based on a chosen date. so I have a date picker assigned to a @ObservedObject var selectDate in my main view

@ObservedObject var selectDate = datepicker()
DatePicker(
    selection: $selectDate.selectedDate,
    in: dateClosedRange,
    displayedComponents: [.date, .hourAndMinute], label: { Text("Is hidden label") })
}

And this class is acting as the middle man. The didSet method is triggering the function to run, confirmed by the print statement in the loadEvents func above.

class datepicker: ObservableObject {
    @Published var selectedDate: Date = Date() {
        didSet {
            print("class datepicker date changed to \(selectedDate)") // This returns the changed dates correctly
            EventsRepository.shared.loadAndUpdateEvents()
        }
    }
}

I've tried passing the new date like this too.

let startOfDay = Calendar.current.startOfDay(for: datepicker.init().selectedDate)

With the same persistent "current date" only result.

How can I pass the new selectedDate to the function whenever the selectDate.selectedDate from the datePicker is changed?

At the moment it doesn't update at all. Always returns events for the current day only.

The print statements contained in the above code in Debug return.

"class datepicker date changed to 2020-08-13 19:23:28 +0000" // YEP That's right. I used datePicker to select this date.
"loadEvents triggered for 2020-08-10 19:23:28 +0000" // NOT updated, ALWAYS shows current date/time as first run. 

So it looks like @Published property is a constant and can not be changed once set. Is there an alternative?

Upvotes: 1

Views: 858

Answers (2)

pawello2222
pawello2222

Reputation: 54516

How can I re-trigger the func loadEvents whenever the selectDate.selectedDate from the datePicker is changed?

You can try using didSet:

class datepicker: ObservableObject{
    @Published var selectedDate: Date = Date() {
        didSet {
            // loadEvents()
        }
    }
}

Tested with Xcode 11.6, iOS 13.6.


EDIT

It looks like you're using two instances of datepicker object. Make sure you're using the same instance in all relevant places.

This object should only be created once:

@ObservedObject var selectDate = datepicker()

Then passed to other places in init.

Upvotes: 2

Procrastin8
Procrastin8

Reputation: 4503

One way to do this, is to actually subscribe to your own publisher when you create your model object.

class DateManager: ObservableObject {
  @Published var selectedDate: Date = .init()

  private var bag: Set<AnyCancellable> = []

  init() {
    $selectedDate // $ prefix gets the projected value, a `Publisher` from `Published<>`
      .receive(on: DispatchQueue.main)
      .sink { [weak self] selectedDate in
        self?.loadEvents(date: selectedDate)
      }
      .store(in: &bag)
  }
}

This will subscribe to that publisher and trigger your API call when it changes. you can get fancy and add debounce or small delays if the user is rapidly changing dates, etc. you now have the full power of combine to control this data flow.

Upvotes: 1

Related Questions