Как идентифицировать 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

Другие вопросы по тегам