Как идентифицировать EKCalendar для хранения выбора календаря пользователя
При работе с календарем пользователей я реализовал EKCalendarChooser, который позволяет пользователю выбирать несколько своих календарей. Выбранные экземпляры календаря извлекаются нормально. Позже я захочу использовать этот выбор, но как я могу сохранить его навсегда?
Мой первый подход состоял в том, чтобы использовать идентификатор календарей и хранить их в виде массива строк для UserDefaults, например
@State private var calendarSelection: [EKCalendar]
// my approach to convert the calendar selection into a storable format (string array of ids)
var selectedIds = [String]()
for calendar in calendarSelection {
selectedIds.append(calendar.calendarIdentifier)
}
// now store the string-array, eg. to user defaults:
UserDefaults.standard.set(selectedIds, forKey: "cids")
К сожалению, это не работает, потому что
calendarIdentifier
не является постоянным идентификатором и поэтому со временем меняется. Как заявляет Apple в своей документации:
При полной синхронизации с календарем этот идентификатор будет утерян. У вас должен быть план работы с календарем, идентификатор которого больше не может быть получен путем кэширования других его свойств.
Как же тогда можно сохранить выбранные пользователем его календари?
2 ответа
У меня тоже такая же проблема. Плохо то, что вы не можете сказать, когда идентификатор изменится. Вот моя работа вокруг...
Я храню идентификатор календаря, название календаря, источник календаря в userDefaults
Я получаю набор календарей, сначала сравнивая идентификатор. Если идентификатор отсутствует в хранилище событий, то сравнение заголовка и источника.
Конечно, вы можете добавить больше свойств, но, на мой взгляд, title + source должно быть достаточно.
У меня есть еще одна часть кода, которая обновляет новый идентификатор в userDefaults.
if userSettings.selectedCalID != [] { //проверяем, пуст массив или нет. Если пусто, не используйте предварительно выбранный календарь.
var selectedCalendarIdentifier : [EKCalendar] = [] for i in userSettings.selectedCalID{ print(i) if let eventStoreID = eventStore.calendar(withIdentifier: i){ selectedCalendarIdentifier.append(eventStoreID) } else { //This is part where calendar identifier has changed or not present in eventstore. Retrive new identifier by checking calendar title AND calendar source. if userSettings.selectedCalTitle != [] && userSettings.selectedCalSource != [] { let calTitle = userSettings.selectedCalTitle[userSettings.selectedCalID.firstIndex(of: i) ?? 0] let calSource = userSettings.selectedCalSource[userSettings.selectedCalID.firstIndex(of: i) ?? 0] print("\(calTitle) - \(calSource)") if let eventStoreCalNewID = eventStore.calendars(for: .event).filter({($0.title == calTitle) && ($0.source.title == calSource)}).first?.calendarIdentifier{ if let eventStoreID = eventStore.calendar(withIdentifier: eventStoreCalNewID){ selectedCalendarIdentifier.append(eventStoreID) } } } } } chooser.selectedCalendars = Set(selectedCalendarIdentifier) }
Хорошо, теперь это работает для меня.
Я храню идентификатор календаря...
func calendarChooserDidFinish(_ calendarChooser: EKCalendarChooser) {
...
// store selected calendar identifier
selectedCalendar = calendarChooser.selectedCalendars.first?.calendarIdentifier
...
}
... затем восстановите его.
func showCalendarChooser() {
...
// check if calendar identifier still exists
if let selectedCalendarIdentifier = eventStore.calendar(withIdentifier: selectedCalendar) {
//select stored calendar
calendarChooser.selectedCalendars = [selectedCalendarIdentifier]
}
...
}
Это только для 1 выбранного календаря (selectionStyle: .single
).
Изменение этого кода на несколько календарей должно быть тривиальным.
Я также проверил, может ли идентификатор календаря измениться... пока без радости. Он оставался неизменным на протяжении всех тестов. Если должно измениться (nil
), календарь не будет выбран, и приложение не выйдет из строя.
HTH