iOS: создание событий в календаре

Сейчас постараюсь обьяснить, как создавать события в календаре. Можно использовать календарь по умолчанию для добавления событий или создать свой, мы будем создавать свой. Так как календарь можно получить только по его идентификатору, то его нужно запомнить после создания календаря. Для этого будем использовать хранилище настроек NSUserDefaults. Так же нужно не забывать что пользователь может в любой момент удалить созданый нами календарь, поэтому всегда нужно проверять получили ли мы дескриптор календаря или нужно создавать его заново.

Доступ к календарю нужно запрашивать у пользователя. Добавление событий будет всегда проходить через вызов метода проверки доступа, но сам запрос у пользователя будет только один раз.

Нужно добавить framework EventKit. Чтобы нам были доступны классы EKCalendar, EKEvent, EKEventStore и т.д. Также в заголовочном файле прописываем импорт #import <EventKit/EventKit.h>

Для проверки доспупа нам нужно создать обьект EKEventStore, вызвать у него метод requestAccessToEntityType, в котором мы указываем события какого типа мы хотим зодавать и функцию обработки ответа пользователя, котороя у нас выводит сообщения если пользователь запретил, или в противном случае вызывает метод добавления события. События календаря бывают двух типов - это непосредственно события EKEntityTypeEvent и напоминания EKEntityTypeReminder.

[[EKEventStore alloc] requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
    if (granted) {
        [self addCalendarEvent];
    } else {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error"
                                                        message:@"Access to calendar forbidden"
                                                       delegate:nil
                                              cancelButtonTitle:@"OK"
                                              otherButtonTitles:nil];
        [alert show];
    }
}];

После того как пользователь даст нам добро на “поковыряться” в его календаре мы проверяем, известен ли нам идентификатор календаря и либо пытаемся получить календарь либо создаем новый. Для начала нам нужно создать обьект EKEventStore, через который мы и получаем доступ к календарям.

EKEventStore *eventStore = [[EKEventStore alloc] init];
EKCalendar *calendar = nil;
NSString *identifier = [[NSUserDefaults standardUserDefaults] valueForKey:@"calendar_identifier"]; // will be nil if not exists

if (identifier) {
    calendar = [eventStore calendarWithIdentifier:identifier]; // get existing calendar
}

Если же идентификатор нам не известен, или календаря с таким идентификатором нет, нужно его создать. При создании нужно указывать source календаря, это может быть локальный календарь и WebDAV или iMobile или какой нибудь другой. Здесь мы будем использовать локальный календарь.

calendar = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:eventStore];
calendar.title = @"CreateCalendarEvent APP";

// set source to local (we use local calendar that not be synced)
for (EKSource *source in eventStore.sources) {
    if (source.sourceType == EKSourceTypeLocal) {
        calendar.source = source;
        break;
    }
}

NSError *error;
[eventStore saveCalendar:calendar commit:YES error:&error];
if (error) {
    NSLog(@"create calendar error: %@", [error description]);
    calendar = nil;
} else {
    [[NSUserDefaults standardUserDefaults] setValue:calendar.calendarIdentifier
                                             forKey:@"calendar_identifier"];
}

В случае увпешного создания календаря добавляем новое событие в него. Для события нужно обязательно указывать начальную дату и конечную, для конечной даты мы будем использовать указаную дату + 2 часа. Так же установим сигнал который должен всплыть пользователю при наступлении события, для этого используем EKAlarm.

EKEvent *event = [EKEvent eventWithEventStore:eventStore];
event.calendar = calendar;
event.title = self.titleText.text;
event.notes = self.noteText.text;
event.startDate = self.datePicker.date;
event.endDate = [self.datePicker.date dateByAddingTimeInterval:3600 * 2]; // +2 hours

// adding alert on date
EKAlarm *alarm = [[EKAlarm alloc] init];
[alarm setAbsoluteDate:self.datePicker.date];
[event addAlarm:alarm];

NSError *error = nil;
[eventStore saveEvent:event span:EKSpanThisEvent commit:YES error:&error];
if (error) {
    NSLog(@"event save error: %@", [error description]);
} else {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Success"
                                                    message:@"event saved"
                                                   delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
    [alert show];
}

Все новые календари и события нужно не забывать сохранять в EKEventStore.

Полный код примера доступен на GitHub.