4

For my app I have to create a Calendar in the user's iCloud account and add events to that calendar.

I am Creating calendar using this:

let newCalendar = EKCalendar(forEntityType: EKEntityTypeEvent, eventStore: EventManager.sharedInstance.eventStore)
    newCalendar.title = "MyAppCalendar"
    let color = UIColor(red: CGFloat(arc4random_uniform(255))/255, green: CGFloat(arc4random_uniform(255))/255, blue: CGFloat(arc4random_uniform(255))/255, alpha: 1)
    newCalendar.CGColor = color.CGColor

    var mySource:EKSource?
    for source in EventManager.sharedInstance.eventStore?.sources() as! [EKSource] {
        if source.sourceType.value == EKSourceTypeCalDAV.value && source.title == "iCloud" {
            mySource = source
            break
        }
    }
    if mySource == nil {
        //crearting alert and displaying to user
        return
    }
    else {
        newCalendar.source = mySource!
    }

    var error:NSError?
    if EventManager.sharedInstance.eventStore!.saveCalendar(newCalendar, commit: true, error: &error) {
        let calendarName = newCalendar.title
        let calendarIdentifier = newCalendar.calendarIdentifier
        //save these in db and server
    }else {
        SharedConstants.handleErrors(error!)
    }

Where EventManager is my class to maintain reference to EKEventStore object instance.

But in Apple documentation it says that the calendarIdentifier changes on syncing.

So my question is how to maintain a reference to this calendar?

Raja Vikram
  • 1,970
  • 15
  • 17
  • Take a look on this answer: http://stackoverflow.com/questions/15912137/what-exactly-constitutes-a-full-calendar-sync-in-ekcalendar/31631405#31631405. Probably it will help. – Vlad Papko Aug 10 '15 at 01:35
  • @Visput thanks for this link, but how do i overcome my issue? – Raja Vikram Aug 12 '15 at 09:48

1 Answers1

3

There are no solution that will work in 100% cases, because as you know calendarIdentifier can be changed. So there is no any unique identifier that will refer to specific calendar all the time.
But it's possible to make solution that will work in most cases. I propose to use such algorithm for referring to specific calendar:
I presume that you have cached calendarIdentifier and title for your calendar.

  1. Iterate through all calendars.
  2. Check if any calendar has identifier that is equal to cached identifier.
  3. If identifiers are equal then you found your calendar.
  4. In other case check if any calendar has title that is equal to cached identifier.
  5. If titles are equal then probably you found your calendar. It can be not true if user replaced titles for your calendar and some another one. I think this scenario has pretty low chance.
  6. In other case you won't be able to find your calendar. It can happen in case when user deletes your calendar.

Here is code snippet for above algorithm:

func eventsCalendarWithIdentifier(identifier: String!, title: String!) -> EKCalendar? {
    var calendarWithIdentifier: EKCalendar? = nil
    var calendarWithTitle: EKCalendar? = nil

    let eventStore = EventManager.sharedInstance.eventStore!
    for aCalendar in eventStore.calendarsForEntityType(EKEntityTypeEvent) as! [EKCalendar] {
        if var anIdentifier = aCalendar.calendarIdentifier {
            if anIdentifier == identifier {
                calendarWithIdentifier = aCalendar
                break
            }
        }

        if var aTitle = aCalendar.title {
            if aTitle == title {
                calendarWithTitle = aCalendar
            }
        }

    }

    return calendarWithIdentifier ?? calendarWithTitle
}

Also it's important to handle events when potential full synch is happened and recreate your calendar instance. It's important because user can delete your calendar while your application is in background, in this case calendar will be invalid.
Here is code snippet for handling such events:

func registerObserver() {
    NSNotificationCenter.defaultCenter().addObserver(self,
        selector: "storeChanged",
        name: EKEventStoreChangedNotification,
        object: nil)
}

func unregisterObserver() {
    NSNotificationCenter.defaultCenter().removeObserver(self,
        name: EKEventStoreChangedNotification,
        object: nil)
}

func storeChanged() {
    let myCalendar = self.eventsCalendarWithIdentifier(cachedIdentifier, title: cachedTitle)
    if myCalendar == nil {
        // Calendar lost.
    }
    // Updated UI if needed.
}
Vlad Papko
  • 13,184
  • 4
  • 41
  • 57
  • Thanks for taking the time to answer me. But i'm looking for a foolproof way to get my calendar from the ios calendar db. Actually i already tired your approach by adding a third constraint of the calendar's `CGColor`, but it is still not foolproof. I will wait for any improvements if possible. – Raja Vikram Aug 13 '15 at 03:52