Как создать и сохранить EKCalendar на ios 6

У меня проблема, когда я создаю свой EKCalendar, и все выглядит хорошо, но потом, когда я перехожу к списку своих календарей, он не появляется. Я также просматриваю свой список календарей в приложении для своего календаря, но он не существует. Любые мысли?

Вот мой код кнопки для создания моего календаря:

- (IBAction)one:(id)sender {
NSString* calendarName = @"My Cal";
EKCalendar* calendar;

// Get the calendar source
EKSource* localSource;
for (EKSource* source in eventStore.sources) {
    if (source.sourceType == EKSourceTypeLocal)
    {
        localSource = source;
        break;
    }
}

if (!localSource)
    return;

calendar = [EKCalendar calendarWithEventStore:eventStore];
calendar.source = localSource;
calendar.title = calendarName;

NSError* error;
bool success= [eventStore saveCalendar:calendar commit:YES error:&error];
if (error != nil)
{
    NSLog(error.description);
    // TODO: error handling here
}
NSLog(@"cal id = %@", calendar.calendarIdentifier);
}

И вот мой код кнопки, чтобы перечислить календарь, но мой новый календарь никогда не включается!

- (IBAction)two:(id)sender {

NSArray *calendars = [eventStore calendarsForEntityType:EKEntityTypeEvent];

for (EKCalendar* cal in calendars){
    NSLog(@"%@",cal.title);
}

}

Заранее благодарю вас!

Ответ 1

Я нашел решение. Проблема в том, что когда календари iCloud включаются, он скрывает локально созданные из приложения календаря. Чтобы обойти эту проблему, решение состоит в том, чтобы добавить новый календарь в источник iCloud:

    for (EKSource *source in self.eventStore.sources)
    {
        if (source.sourceType == EKSourceTypeCalDAV && 
           [source.title isEqualToString:@"iCloud"]) //Couldn't find better way, if there is, then tell me too. :)
        {
            localSource = source;
            break;
        }
    }

    if (localSource == nil)
    {
        for (EKSource *source in self.eventStore.sources)
        {
            if (source.sourceType == EKSourceTypeLocal)
            {
                localSource = source;
                break;
            }
        }
    }

Ответ 2

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

Как написано в документации:

/* 
 * Returns the calendar that events should be added to by default, 
 * as set in the Settings application.
 */
@property EKCalendar *defaultCalendarForNewEvents; 

Итак, я использую этот код для получения правильного EKSource:

EKSource *theSource = [self.eventStore defaultCalendarForNewEvents].source;

НО, если вы используете другой календарь, например Gmail (или Yahoo и т.д.), вы не можете добавить свой календарь в свой источник.

В этом редком случае я использую полный поиск:

EKSource *theSource;
for (EKSource *source in eventStore.sources) {
    if (source.sourceType == EKSourceTypeSubscribed) {
        theSource = source;
        break; // stop when source is found
    }
}

Ответ 3

Пробовали ли вы сначала проверить настройку авторизации, чтобы убедиться, что пользователь дал разрешение на доступ к хранилищу?

Для EKEventStore документации:

+ (EKAuthorizationStatus)authorizationStatusForEntityType:(EKEntityType)entityType

- (void)requestAccessToEntityType:(EKEntityType)entityType completion:(EKEventStoreRequestAccessCompletionHandler)completion

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

Ответ 4

Локальный магазин может не поддерживать события. Это воспроизводится, если включен iCloud.

Это самое надежное решение, которое я смог найти, без жесткого кодирования любых предположений:

    let calendar = EKCalendar(forEntityType: .Event, eventStore: eventStore)

    if eventStore.sources.count == 0 { // reproducible after Reset Content and Settings
        calendar.source = EKSource()
    }
    else {
        calendar.source = eventStore.defaultCalendarForNewEvents.source
    }

    eventStore.saveCalendar(calendar, commit: true)

Ответ 5

У меня была такая же проблема. Я сделал так, как предлагал шестой вариант, и приложение попросило разрешения. Это решило одну часть, но календарь еще не появился, но создавался в соответствии с NSLogs. У меня был календарь Exchange (у меня не было iCloud) на моем телефоне, и мне пришлось отключить его. Как только это было удалено, оно появилось как локальный календарь. Когда я вернулся, чтобы снова добавить Exchange, он спросил, хочу ли я сохранить оба, и теперь появляются оба календаря. Вот мой код ниже.

#import "ViewController.h"
#import <EventKit/EventKit.h>
#import <EventKitUI/EventKitUI.h>

@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad
{
[super viewDidLoad];  

EKEventStore *store = [[EKEventStore alloc] init];
EKSource *localSource = nil;
for (EKSource *source in store.sources)
{
    if (source.sourceType == EKSourceTypeCalDAV && [source.title isEqualToString:@"iCloud"])
    {
        localSource = source;
        break;
    }
}
if (localSource == nil)
{        
    for (EKSource *source in store.sources) {
        if (source.sourceType == EKSourceTypeLocal)
        {
            localSource = source;
            break;
        }
    }
}

EKEventStore *es = [[EKEventStore alloc] init];
[es requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
    /* This code will run when uses has made his/her choice */

    if (error)
    {
        // display error message here
    }
    else if (!granted)
    {
        // display access denied error message here
    }
    else
    {
        // access granted          
    }


}];

//NSString *identifier; //Use to create for the first time and store somewhere
NSString *identifier = @"704A1304-5213-4AB3-9C7B-F6B59E3454BB"; //Stored version

//Create the calendar
EKCalendar *cal;
if (identifier == nil)
{
    cal = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:store];

    cal.title = @"Demo1 Calendar";
    cal.source = localSource;
    [store saveCalendar:cal commit:YES error:nil];
    NSLog(@"cal id = %@", cal.calendarIdentifier);

} else {
    //Calendar already exists!
    cal = [store calendarWithIdentifier:identifier];
    NSLog(@"cal id = %@", cal.calendarIdentifier);
}

//calendar properties
NSLog(@"%@", cal);

//Add Event to Calendar
NSLog(@"Adding event!");
EKEventStore *eventStore = [[EKEventStore alloc] init];

EKEvent *event  = [EKEvent eventWithEventStore:eventStore];
event.title     = @"Event3";

NSDate *startDate = [NSDate date];
event.calendar = cal;
event.startDate = startDate;
event.endDate = [startDate dateByAddingTimeInterval:3600];

NSError *error = nil;
BOOL result = [eventStore saveEvent:event span:EKSpanThisEvent commit:YES error:&error];
if (result) {
    NSLog(@"Saved event to event store.");
} else {
    NSLog(@"Error saving event: %@.", error);
}

}

Ответ 6

Решение Массимо Оливиеро не помогло мне. Я была такая же проблема. Я создал Календарь после вызова requestAccessToEntityType.
Что для меня работало после получения разрешения, я повторно инициализировал объект EventStore. Это было похоже на то, что разрешения никогда не расстраивались.

[[CalendarManager sharedManager].eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
    if (granted && error == nil) {
        // Store the returned granted value.
        [CalendarManager sharedManager].eventsAccessGranted = granted;
        if (![CalendarManager sharedManager].calendarCreated) {
            [[CalendarManager sharedManager] createCalendar];
        }
    }
    else{
        // In case of error, just log its description to the debugger.
        DebugLog(@"%@", [error localizedDescription]);
    }
}];

В CalendarManager

- (void)createCalendar {

_eventStore = nil;
_eventStore = [EKEventStore new];

// Create a new calendar.
EKCalendar *calendar = [EKCalendar calendarForEntityType:EKEntityTypeEvent
                                              eventStore:self.eventStore];

// Set the calendar title.
calendar.title = CALENDAR_NAME;

EKSource *theSource;

// First: Check if the user has an iCloud source set-up.
for (EKSource *source in self.eventStore.sources) {
    if (source.sourceType == EKSourceTypeCalDAV && [source.title isEqualToString:@"iCloud"]) {
        theSource = source;
        break;
    }
}

// Second: If no iCloud source is set-up / utilised, then fall back and use the local source.
if (theSource == nil) {
    for (EKSource *source in self.eventStore.sources) {
        if (source.sourceType == EKSourceTypeLocal)  {
            theSource = source;
            break;
        }
    }
}

calendar.source = theSource;

// Save and commit the calendar.
NSError *error;
[_eventStore saveCalendar:calendar commit:YES error:&error];

// If no error occurs then turn the editing mode off, store the new calendar identifier and reload the calendars.
if (error == nil) {
    self.calendarCreated = YES;
}
else {
    self.calendarCreated = NO;
    // Display the error description to the debugger.
    DebugLog(@"%@", [error localizedDescription]);
}}

Ответ 7

Я бы не рекомендовал главный ответ, так как он полагается на проверку "iCloud" как имени, что может быть изменено пользователем. Если вы просто хотите, чтобы календарь был сохранен, и вы не всегда заботитесь о том, какой источник он получает, вы можете сделать это:

EKCalendar *calendar = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:eventStore];
calendar.title = @"Calendar name";

NSError *calendarError = nil;
for (EKSource *source in eventStore.sources) {
    // We know the birthday source is read-only
    if (source.sourceType == EKSourceTypeBirthdays) {
        continue;
    }

    calendar.source = source;
    [eventStore saveCalendar:calendar commit:YES error:&calendarError];

    // If saving succeeded, we break, otherwise we try a new source
    if (!calendarError) {
        break;
    }
}