
Many apps take advantage of the Events or Reminders on iOS. This is very useful when wanting to give the user the ability to add an event to the calendar or a reminder.
This is quite simple to do, so let’s take a look. Create an NSObject Class to manage all our EventKit stuff and add the following:
#import <EventKit/EventKit.h>
@property (strong, readonly) EKEventStore *eventStore;
@property (assign, readonly) BOOL eventAccess;
@property (assign, readonly) BOOL reminderAccess;
So far we are simply importing the EventKit, which by the way you must add as Link Library in Target Settings, Summary. Then we add a property to access the EventStore and some booleans.
– (id) init {
self = [super init]; if (self) {_eventStore = [[EKEventStore alloc] init];
[_eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (granted) { _eventAccess = YES;
} else {
NSLog(@”Event access not granted: %@”, error);
} }];
[_eventStore requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError *error) {
if (granted) { _reminderAccess = YES;
} else {
NSLog(@”Reminder access not granted: %@”,error); }
}]; }
return self; }
Now we can determine whether we have access to that store or not. Now create a ViewController which will actually use that class:
#import “EventKitController.h”
EventKitController *_eventKitController;
– (id) initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) {
…
_eventKitController = [[EventKitController alloc] init]; }
return self; }
If you run this, your device will ask you if you want this app to access your EventStore. Now let’s add some events. To do so you must select a calendar and then create the event in order to save it. This is how you access calendars:
NSArray * allCalendars = [_eventStore calendarsForEntityType:EKEntityMaskEvent |
EKEntityMaskReminder];
NSMutableArray * writableCalendars = [NSMutableArray array]; for (EKCalendar * calendar in allCalendars) {if (calendar.allowsContentModifications) { [writableCalendars addObject:calendar];
} }
Ok so let’s create an event:
//First create the event and then save it
EKEvent *event = [EKEvent eventWithEventStore:eventStore]; event.title = @”My Coding Event”;
event.startDate = startDate;
event.endDate = endDate;event.calendar = eventStore.defaultCalendarForNewEvents;
NSError *err;
BOOL saved = [eventStore saveEvent:event span:EKSpanThisEvent commit:YES error:&err];if (!saved) {
NSLog(@”Error creating the event”);}
This is pretty simple. Let’s modify the EventKit NSObject class we created to handle this kind of code:
– (void) addEventWithName:(NSString*) eventName startTime:(NSDate*) startDate endTime:(NSDate*) endDate {
if (!_eventAccess) {
NSLog(@”No event acccess!”); return;}
//1. Create an Event EKEvent *event = [EKEvent
eventWithEventStore:self.eventStore]; event.title = eventName;
//3. Set the start and end date
event.startDate = startDate; event.endDate = endDate;
//4. Set an alarm (This is optional)
EKAlarm *alarm = [EKAlarm alarmWithRelativeOffset:-1800]; [event addAlarm:alarm];
//5. Add a note (This is optional)
event.notes = @”This will be exciting”;
//6. Specify the calendar to store the eventevent.calendar=self.eventStore.defaultCalendarForNewEvents;
NSError *err;
BOOL success = [self.eventStoresaveEvent:event span:EKSpanThisEvent commit:YES error:&err];
if (!success) {
NSLog(@”There was an error saving event: %@”, err);} }
Now declare the class in the EventKit NSObject Class by adding this to its interface:
-(void)addEventWithName:(NSString*)eventName startTime:(NSDate*)startDate endTime:(NSDate*)endDate;
and finally add an event from your viewcontroller class by calling this:
[_eventKitController addEventWithName:self.conference.name startTime:self.conference.startDate endTime:self.conference.endDate];
That’s it for events! There are other options you can look at such as:
//1
EKRecurrenceRule *recurrenceRule =
[[EKRecurrenceRule alloc] initRecurrenceWithFrequency:EKRecurrenceFrequencyMonthly interval:1 end:nil];//2
event.recurrenceRules = @[recurrenceRule];
EKRecurrenceEnd *end = [EKRecurrenceEnd recurrenceEndWithEndDate:endDate]; //or
EKRecurrenceEnd *end = [EKRecurrenceEnd recurrenceEndWithOccurrenceCount:5];
In which case you could modify the EventKit NSObject class to have this method:
– (void) addRecurringEventWithName:(NSString*) eventName startTime:(NSDate*) startDate endTime:(NSDate*) endDate {
if (!_eventAccess) {
NSLog(@”No event acccess!”); return;}
//1. Create an Event
EKEvent *event = [EKEvent eventWithEventStore:self.eventStore];
//2. Set the title
event.title = eventName;
//3. Set the start and end date
event.startDate = startDate; event.endDate = endDate;
//4. Set an alarm (This is optional)
EKAlarm *alarm = [EKAlarm alarmWithRelativeOffset:-1800];
[event addAlarm:alarm];
//5. Add a note (This is optional)event.notes = @”This will be exciting”;
//6. Add the recurrrence rule.
EKRecurrenceRule *rule = [[EKRecurrenceRule alloc]
initRecurrenceWithFrequency: EKRecurrenceFrequencyYearly interval:1 end:nil];
event.recurrenceRules = @[rule];
//7. Specify the calendar to store the event to
event.calendar = self.eventStore.defaultCalendarForNewEvents;
NSError *err;
BOOL success = [self.eventStoresaveEvent:event span:EKSpanThisEvent commit:YES error:&err];
if (!success) {
NSLog(@”There was an error saving event: %@”, err);} }
So you would have to declare:
-(void)addRecurringEventWithName:(NSString*)eventName startTime:(NSDate*)startDate endTime:(NSDate*)endDate;
and call it like so:
[_eventKitController addRecurringEventWithName:self.conference.name startTime:self.conference.startDate endTime:self.conference.endDate];
Finally you could delete events by adding a queue to your NSObject class:
dispatch_queue_t _fetchQueue;
and define it in viewDidLoad:
_fetchQueue = dispatch_queue_create(“com.conferencePlannerForGeeks.fetchQueue”, DISPATCH_QUEUE_SERIAL);
and add the delete method like so:
– (void) deleteEventWithName:(NSString*) eventName startTime:(NSDate*) startDate endTime:(NSDate*) endDate {
if (!_eventAccess) {
NSLog(@”No event acccess!”); return;
}
dispatch_async(_fetchQueue, ^{//1. Create a prediate to find the EKEvent to delete
NSPredicate *predicate = [self.eventStore
predicateForEventsWithStartDate:startDate endDate:endDate
calendars: @[self.eventStore.defaultCalendarForNewEvents]];NSArray *events =
[self.eventStore eventsMatchingPredicate:predicate];//2. Post filter the events array
NSPredicate *titlePredicate = [NSPredicate
predicateWithFormat:@”title matches %@”,
eventName]; events = [events
filteredArrayUsingPredicate:titlePredicate];
//3. Delete each of these events
NSError *err;
for (EKEvent *event in events) {[self.eventStore
removeEvent:event span:event.hasRecurrenceRules ? EKSpanFutureEvents:EKSpanThisEvent commit:NO error:&err];}
BOOL success = [self.eventStore commit:&err]; if (!success) {
NSLog(@”There was an error deleting event”); }
});
if (!_eventAccess) {NSLog(@”No event acccess!”);
return; }
}
In the end you would declare it:
-(void)deleteEventWithName:(NSString*)eventName startTime:(NSDate*)startDate endTime:(NSDate*)endDate;
and call it like so:
[_eventKitController deleteEventWithName:self.conference.name startTime:self.conference.startDate endTime:self.conference.endDate];
Reminders are a bit different but still quite simple. To create a basic reminder you do:
//1
EKReminder *reminder =
[EKReminder reminderWithEventStore:eventStore]; reminder.title = @”Creating my first reminder”; reminder.calendar =
[eventStore defaultCalendarForNewReminders];
//2
NSError *err; BOOL success =
[eventStore saveReminder:reminder commit:YES error:&err];
if (!success) {
NSLog(@”Error creating reminder”);}
Notice you are still using the EventStore. So we can still use our EventKit NSObject Class and say:
– (void) addReminderWithTitle:(NSString*) title dueTime:(NSDate*) dueDate {
if (!_reminderAccess) {
NSLog(@”No reminder acccess!”); return;}
//1.Create a reminder
EKReminder *reminder = [EKReminder
reminderWithEventStore: self.eventStore];
//2. Set the title
reminder.title = title;
//3. Set the calendar
reminder.calendar =
[self calendarForReminders];//4. Extract the NSDateComponents from the dueDate
NSCalendar *calendar =
[NSCalendar currentCalendar];NSUInteger unitFlags = NSEraCalendarUnit |
NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSDateComponents *dueDateComponents = [calendar components:unitFlags fromDate:dueDate];
//5. Set the due date
reminder.dueDateComponents = dueDateComponents;
//6. Save the reminder
NSError *err;
BOOL success = [self.eventStoresaveReminder:reminder commit:YES error:&err];
if (!success) {
NSLog(@”There was an error saving the reminder %@”,
} }
If you want to use a Calendar Title you can define it like so:
#define kRemindersCalendarTitle @”My Coding reminders”
Now you code for that calendar like so:
– (EKCalendar*) calendarForReminders {
//1
for (EKCalendar *calendar in [self.eventStore
calendarsForEntityType:EKEntityTypeReminder]) {
if ([calendar.title isEqualToString:kRemindersCalendarTitle]) {
return calendar; }
}
//2
EKCalendar *remindersCalendar = [EKCalendar
calendarForEntityType:EKEntityTypeReminder eventStore:self.eventStore];
remindersCalendar.title = kRemindersCalendarTitle; remindersCalendar.source =
self.eventStore.defaultCalendarForNewReminders.source;
NSError *err;
BOOL success = [self.eventStoresaveCalendar:remindersCalendar commit:YES error:&err];
if (!success) {
NSLog(@”There was an error creating the reminderscalendar”);
return nil; }
return remindersCalendar; }
Declare the method in the interface:
-(void)addReminderWithTitle:(NSString*)title dueTime:(NSDate*)dueDate;
Now call the method:
[_eventKitController addReminderWithTitle:
[NSString stringWithFormat:@”Buy your %@ ticket”, self.conference.name]
dueTime:[NSDate date]];
Voila, you’ve got calendar interaction for your app!