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

时间:2020-08-09 22:24:44

标签: swift swiftui eventkit

已更新

我正在使用EventKit从IOS日历中提取事件。效果很好。

这里是检索事件的类函数。

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

这个班子充当中间人。 didSet方法正在触发该函数的运行,已通过上面loadEvents函数中的print语句确认。

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传递给函数?

目前,它根本不更新。始终仅返回当天的事件。

上面的代码在Debug中返回的打印语句返回。

"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属性是一个常量,一旦设置就无法更改。有其他选择吗?

2 个答案:

答案 0 :(得分:2)

无论何时,如何重新触发func loadEvents 从datePicker中选择selectDate.selectedDate吗?

您可以尝试使用didSet

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

在Xcode 11.6,iOS 13.6上进行了测试。


编辑

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

该对象只能创建一次:

@ObservedObject var selectDate = datepicker()

然后传递到init中的其他位置。

答案 1 :(得分:1)

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

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或稍加延迟。现在,您可以完全结合使用来控制此数据流。