9

I am trying to create a Calendar, not a calendar event but a Calendar. I can't get a local source and my app crashes.

Here is my code:

let newCalendar = EKCalendar(for: .event, eventStore: eventStore)

newCalendar.title = "Some Calendar Name"

let sourcesInEventStore = eventStore.sources

newCalendar.source = sourcesInEventStore.filter{
            (source: EKSource) -> Bool in
            source.sourceType.rawValue == EKSourceType.local.rawValue
            }.first!

I have my iCloud completely turned off and still can't get a local source.

I'm also trying to get this to work with iCloud turned on, I came up with this code, but it does not work

for let source in eventStore.sources
        {
            if(source.sourceType == EKSourceType.calDAV && source.title == "iCloud")
            {
                newCalendar.source = source
            }
        }

        if(newCalendar.source == nil)
        {
            for let source2 in eventStore.sources
            {
                if(source2.sourceType == EKSourceType.local)
                {
                    newCalendar.source = source2
                }
            }
        }
JAL
  • 41,701
  • 23
  • 172
  • 300
user979331
  • 11,039
  • 73
  • 223
  • 418
  • I'm having this same problem. At issue is disappearance of the 'local' calendar. I found that the 'On My iPhone' calendar group is also gone from my Calendars list in the Calendar app. Hmm... Now to find out where, oh where, has it gone? It's always been there before... (iOS 11.4.1) Researching... – leanne Sep 20 '18 at 01:22

1 Answers1

6

A few issues:

Your code is crashing because you're force-unwrapping first from an array that is empty. Here are a few suggestions to make sure that the array of EKSource objects returns a non-empty array.

First, ask the user for access to their calendar using requestAccess(to:) on an EKEventStore instance. Secondly, use an if let to unwrap a potentially optional value from your filtered array:

let eventStore = EKEventStore()

eventStore.requestAccess(to: .event) { (granted, error) in
    if granted {
        let newCalendar = EKCalendar(for: .event, eventStore: eventStore)

        newCalendar.title = "Some Calendar Name"

        let sourcesInEventStore = eventStore.sources

        let filteredSources = sourcesInEventStore.filter { $0.sourceType == .local }

        if let localSource = filteredSources.first {
            newCalendar.source = localSource
        } else {
            // Somehow, the local calendar was not found, handle error accordingly
        }

    } else {
        // check error and alert the user
    }
}
JAL
  • 41,701
  • 23
  • 172
  • 300
  • Gonna give this a try. – user979331 Jan 30 '17 at 14:09
  • I tried this, I dont get any errors and now the alert pops up asking if its okay to use calendar, however there is still no local source :( It goes into the else statement `// Somehow, the local calendar was not found, handle error accordingly` How come I am getting no local source? – user979331 Jan 30 '17 at 19:25
  • @user979331 The alert is normal, you need to ask the user for permission to use their calendar. I have no idea why there would be no local calendars. Are there any calendars at all in sourcesInEventStore? – JAL Jan 30 '17 at 20:25
  • 1
    @user979331 I was wondering if your code lives in a method that its execution is ended before the requestAcces block is fired by any chance. It's on a different thread which would mean the eventStore you initialized may go away by that point so the EKCalendar you create has a nil eventStore. I'm suggesting this because (after adding the right info.plist description for request of calendars), everything worked fine when I used this code. – Prientus Jan 31 '17 at 22:22
  • Yes, make sure you put all of your logic in the `requestAccess(to:)` block or make your other code asynchronous. – JAL Jan 31 '17 at 22:56
  • Okay, that works I am now able to get my sources, now I have a new problem `let filteredSources = sourcesInEventStore.filter { $0.sourceType == .local }` returns 0 however if I do `newCalendar.source = sourcesInEventStore[1]` it works cause 0 is a birthday calendar and it wont let me add a calendar to it – user979331 Feb 01 '17 at 03:36
  • @user979331 1 would be the second element, not the first. What are all of the calendars in that array? Did you try a different device? – JAL Feb 01 '17 at 03:53
  • Yes I know the 1 would be the second element, the 0 calendar is called Birthday Calendar and won't let me add to it. – user979331 Feb 01 '17 at 15:12
  • @user979331 Oh I misread your comment, I thought you meant `1` was the birthday calendar. – JAL Feb 01 '17 at 16:09