#swift #swiftui #eventkit
#swift #swiftui #eventkit
Вопрос:
ОБНОВЛЕНО
Я извлекаю события из календаря IOS с помощью EventKit. Работает отлично.
Вот функция класса, которая извлекает события.
@ObservedObject var selectDate = datepicker() // does NOT update as expected.
func loadEvents(completion: @escapin& (([EKEvent]?) -&&t; 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(matchin&: predicate)
completion(events)
print("loadEvents tri&&ered for (self.selectDate.selectedDate)") // This ALWAYS returns the current date
}) {
completion(nil)
}
}
Я хочу обновить результаты на основе выбранной даты.
итак, у меня есть средство выбора даты, назначенное переменной @ObservedObject selectDate в моем основном представлении
@ObservedObject var selectDate = datepicker()
DatePicker(
selection: $selectDate.selectedDate,
in: dateClosedRan&e,
displayedComponents: [.date, .hourAndMinute], label: { Text("Is hidden label") })
}
И этот класс действует как посредник. didSet
Метод запускает функцию для запуска, что подтверждается инструкцией print в loadEvents
функции выше.
class datepicker: ObservableObject {
@Published var selectedDate: Date = Date() {
didSet {
print("class datepicker date chan&ed to (selectedDate)") // This returns the chan&ed dates correctly
EventsRepository.shared.loadAndUpdateEvents()
}
}
}
Я тоже пробовал передавать новую дату подобным образом.
let startOfDay = Calendar.current.startOfDay(for: datepicker.init().selectedDate)
С тем же постоянным результатом только «текущая дата».
Как я могу передавать новую выбранную дату в функцию всякий раз, когда изменяется selectDate.selectedDate из DatePicker?
На данный момент она вообще не обновляется. Всегда возвращает события только за текущий день.
Инструкции print, содержащиеся в приведенном выше коде, возвращаются в Debu&.
"class datepicker date chan&ed to 2020-08-13 19:23:28 0000" // YEP That's ri&ht. I used datePicker to select this date.
"loadEvents tri&&ered for 2020-08-10 19:23:28 0000" // NOT updated, ALWAYS shows current date/time as first run.
Таким образом, похоже, что свойство @Published является константой и не может быть изменено после установки. Есть ли альтернатива?
Ответ №1:
Как я могу повторно запускать loadEvents функции всякий раз, когда изменяется selectDate.selectedDate из DatePicker?
Вы можете попробовать использовать didSet
:
class datepicker: ObservableObject{
@Published var selectedDate: Date = Date() {
didSet {
// loadEvents()
}
}
}
Протестировано с Xcode 11.6, iOS 13.6.
Редактировать
Похоже, что вы используете два экземпляра datepicker
object. Убедитесь, что вы используете один и тот же экземпляр во всех соответствующих местах.
Этот объект должен быть создан только один раз:
@ObservedObject var selectDate = datepicker()
Затем передается в другие места в init
.
Комментарии:
1. Это определенно не сработает. Фактическим типом здесь является
Published<&&t;
оболочка свойства, которая технически никогда не устанавливается снова.2. @Procrastin8 Нет, вы ошибаетесь. Пожалуйста, запустите мой код на игровой площадке (вы можете
didSet
) и посмотрите, что произойдет. Я понимаю, что способ объединения может показаться вам лучше, но, пожалуйста, не критикуйте мое решение, не протестировав его сначала.3. Я могу подтвердить с помощью инструкций print, что
didSet
метод запускает функции для запуска. Но новая выбранная дата не передается этим функциям. Похоже,Published
это одноразовая сделка, как предполагает @Procrastin8. Я просмотрел другое предложенное решение, но не смог реализовать его правильно (я очень новичок, так что это, безусловно, моя ошибка) Но посколькуdidSet
выполняется работа по запуску функции, единственной оставшейся проблемой является передача новой даты. Есть ли другая альтернативаPubished
?4. @My4Paws Трудно точно сказать, что вы делаете. Вы можете попробовать передать
selectedDate
вloadEvents
качестве параметра.5. @pawello2222 Спасибо, я обновил вопрос, чтобы лучше показать, что происходит.
Ответ №2:
Один из способов сделать это — фактически подписаться на вашего собственного издателя при создании объекта модели.
class DateMana&er: ObservableObject {
@Published var selectedDate: Date = .init()
private var ba&: Set<AnyCancellable&&t; = []
init() {
$selectedDate // $ prefix &ets the projected value, a `Publisher` from `Published<&&t;`
.receive(on: DispatchQueue.main)
.sink { [weak self] selectedDate in
self?.loadEvents(date: selectedDate)
}
.store(in: amp;ba&)
}
}
Это приведет к подписке на этого издателя и запуску вашего вызова API при его изменении. вы можете проявить фантазию и добавить debounce
или небольшие задержки, если пользователь быстро меняет даты и т.д. теперь у вас есть все возможности combine для управления этим потоком данных.