如何在更新变量时重新触发功能

How to re-trigger function whenever a variable is updated

已更新

我正在使用 EventKit 从 IOS 日历中提取事件。干得好。

这是检索事件的 class 函数。

@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)
    }
}

我想根据所选日期更新结果。 所以我在主视图

中将日期选择器分配给@ObservedObject var selectDate
@ObservedObject var selectDate = datepicker()
DatePicker(
    selection: $selectDate.selectedDate,
    in: dateClosedRange,
    displayedComponents: [.date, .hourAndMinute], label: { Text("Is hidden label") })
}

而这个class是充当中间人的角色。 didSet 方法将函数触发到 运行,由上面 loadEvents 函数中的打印语句确认。

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()
        }
    }
}

我也试过这样传递新日期。

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

只有相同的持续“当前日期”结果。

每当 datePicker 中的 selectDate.selectedDate 发生变化时,如何将新的 selectedDate 传递给函数?

目前完全没有更新。始终仅在当天发生 returns 事件。

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. 

所以看起来@Published 属性 是一个常量,一旦设置就无法更改。有其他选择吗?

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

您可以尝试使用 didSet:

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

使用 Xcode 11.6、iOS 13.6 测试。


编辑

看起来您正在使用 两个 datepicker 对象实例。确保您在所有相关位置使用相同的实例

该对象只应创建一次:

@ObservedObject var selectDate = datepicker()

然后传到init的其他地方。

实现此目的的一种方法是在创建模型对象时实际订阅您自己的发布者。

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)
  }
}

这将订阅该发布者并在它发生变化时触发您的 API 调用。如果用户正在快速更改日期等,您可以想象并添加 debounce 或小的延迟。您现在拥有 combine 的全部功能来控制此数据流。