5

I'm trying to use Eventkit to access Mac Calendar. Access is successfully requested but I keep getting nil or an empty array of calendar or events, even though I have several calendars and many eventsin local calendar, iCloud calendar, and Google calendar in the app.
The output I get from the following code is: On My Mac [] []

    let sources = eventStore.sources
    for source in sources{
        print(source.title)
        for calendar in source.calendars(for: .event){
            print(calendar.title)
        }
    }

    let calendars = eventStore.calendars(for: .event)
    let predicate = self.eventStore.predicateForEvents(withStart: startDate, end: endDate, calendars: nil)
    let events = self.eventStore.events(matching: predicate)
    print(calendars)
    print(events)

And if I try to create and save a calendar from code, then I'm getting error: Error Domain=EKErrorDomain Code=5 "Attempted to save when persistence was unavailable" UserInfo={NSLocalizedDescription=Attempted to save when persistence was unavailable}

  • From the doc: https://developer.apple.com/documentation/eventkit/ekerror/code/internalfailure this error code "5" is an internal error. Secondly, "The output I get from the following code is: On My Mac [] []" you have 4 print statements, but show here in the question output only for 2 – art-divin Sep 10 '18 at 15:32
  • @art-divin the second print statement is never executed as there are no calendars. – Alex Coplan Sep 10 '18 at 18:59

3 Answers3

8

After lots of trial and error, I found the answer.

You need to set the com.apple.security.personal-information.calendars key to YES in your entitlements file, even if your app is not sandboxed. There is a bug in Apple's implementation of EventKit that prevents your app getting access to calendars if it does not set this key, even if the sandbox is disabled.

Alex Coplan
  • 13,211
  • 19
  • 77
  • 138
0

I might be wrong but you are missing one parameter in your predicate you are passing in nil so there is nothing to sort essentially no output. Try changing your code to:

 let sources = eventStore.sources
    for source in sources{
        print(source.title)
        for calendar in source.calendars(for: .event){
            print(calendar.title)
        }
    }

    let calendars = eventStore.calendars(for: .event)
    let predicate = self.eventStore.predicateForEvents(withStart: startDate, end: endDate, calendars: calendars)  //change here
    let events = self.eventStore.events(matching: predicate)
    print(calendars)
    print(events)
AD Progress
  • 4,190
  • 1
  • 14
  • 33
  • This change is sensible, but the root cause of this issue is that the calendars are not being enumerated when eventStore.calendars() is called, due to a permissions error (see my answer). – Alex Coplan Sep 10 '18 at 18:42
  • Thank you for the clarification. Good that you have managed to get to the root cause of the issue. – AD Progress Sep 11 '18 at 04:08
0

Try this method

Create and Get Calendar

func getCalendar() -> EKCalendar? {
        let defaults = UserDefaults.standard
    
        if let id = defaults.string(forKey:"calendarID") {
            return eventStore.calendar(withIdentifier: id)
          } else {
            let calendar = EKCalendar(for: .event, eventStore: eventStore)
    
               calendar.title = "Calendar Title"
               calendar.cgColor = UIColor.blue
               calendar.source = self.eventStore.defaultCalendarForNewEvents!.source
    
             do {
                 try eventStore.saveCalendar(calendar, commit: true)
                 defaults.set(calendar.calendarIdentifier, forKey: "calendarID")
    
                 print("Created calander")
               } catch let error as NSError {
               print("failed to Create calendar with error : \(error)")
               }
            
    
              return calendar
          }
      }
Furkan
  • 306
  • 4
  • 17