Как создать и сохранить 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;
}
}