Creating calendars and events using EventKit on iOS 6+

I know calendar in iOS is not the most essential part. Although, I think this part of iOS is not covered in many tutorials and a lot of them are for old iOS version using already deprecated methods and because recently I wanted to implement adding events to calendar in my iOS app and although the process is quiet simple it isn't really easy to put all the information you need together.

Each event/reminder has to be assigned to some calendar and each calendar has attributes like identifier, title, type of storage (local, iCloud, CALDAV, …) and so on. Of course, you can create new calendars or use existing ones.

Wrong way

In some tutorials I saw quiet weird approach where you iterate all existing calendars and use the first one that is writable and is the type you want like this:

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
EKCalendar *calendar;
// I strongly NOT recommended to use this
NSArray* calendars = [eventStore calendarsForEntityType:EKEntityTypeEvent];
for (EKCalendar *cal in calendars) {
    if (cal.type == EKCalendarTypeLocal && [cal allowsContentModifications]) {
        calendar = cal;
        break;
    }
}

This is very straight forward and looks very simple. I iterate all exiting calendars and look for the first one that is type EKCalendarTypeLocal (calendar saved locally on device) and is writable. On my iPhone 4 it was calendar called "Work". Disadvantage of this approach is that it completely messes user's calendar and even if you delete your app it stays in there. Please, never do this.

Correct way

It probably makes more sense to first create a calendar only for my app and then add events there. I think this part has changed in iOS 6 so if your app is based on an older SDK it might not work.

First I have to ask for user permission to access calendars. I'm interested only in events right now, that's the EKEntityTypeEvent:

 1 
 2 
 3 
 4 
if (eventStore == nil) {
    eventStore = [[EKEventStorealloc] init];
}
[eventStore requestAccessToEntityType:EKEntityTypeEvent completion:callbackMethod];

Next, I'm going to make a helper class MyCalendar to handle my calendar and events. In pseudocode it will do following:

if (calendar exist)
    get calendar by its identifier
else
    create a new calendar
    store its identifier

if (calendar doesn't exist)
    something's wrong, return

create event
save event

Just remember that if you want to use the same calendar for all your events you have to store its identifier. I'm going to save it into NSUserDefaults because it's probably the easiest way of saving single key-value data in iOS.

Another thing that complicates the entire process a little bit is that requesting access to calendar is asynchronous. Therefore it doesn't return just YES or NO but you have to pass a block. See use case bellow for better overview.

I put source codes it on gist.github.com and tried to write comments everywhere I thought it's appropriate.

… and of course header file:

Typical use case might look like this:

Conclusion

I'm not sure everything in this tutorial is really the best practice, but this is what makes sense to me. If you find some better way of coins something, leave me a comment, I would like to see it.

blog comments powered by Disqus