iOS EKEvent Store在循环中重新创buildiCloud日历,不会保存本地。

我有一个奇怪的问题EKEventStore,iCloud和本地日历。 如果启用了iCloud,则会创build日历,并按照您的预期将事件保存到日历中。 如果iCloud已closures,并且您尝试保存事件,则不会发生任何事情,但是设备会每3-5秒循环创build一次iCloud日历,直到将iCloud重新打开,然后所有这些日历都以重复的forms涌入iCloud。 我正在使用几乎所有在这里被引用的确切代码以及苹果文档。 我完全被困在为什么它不工作,一般EKEventStore似乎很less有文档。

//••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••#编辑标记 – 保存事件//••••••••••••••••••••••••••••••••••••••• ••••

-(void)saveEventWithDate:(NSDate *)startDate endDate:(NSDate *)endDate { AppData *theData = [self theAppData]; if([self checkIsDeviceVersionHigherThanRequiredVersion:@"6.0"]) { [eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) { // iOS 6 Support if (granted){ NSLog(@"Access Granted"); } else { NSLog(@"Access Not Granted"); } }]; } EKEvent *event = [EKEvent eventWithEventStore:eventStore]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; if ([eventStore calendarWithIdentifier:[defaults objectForKey:@"My Calendar"]] != nil) // Calendar Existed { event.calendar = [eventStore calendarWithIdentifier:[defaults objectForKey:@"My Calendar"]]; NSLog(@"Calendar Existed"); } else { // Create Calendar EKSource *theSource = nil; for (EKSource* src in eventStore.sources) { if ([src.title isEqualToString:@"iCloud"]) { theSource = src; break; } if (src.sourceType == EKSourceTypeLocal && theSource==nil) { theSource = src; break; } } [self setupCalendarWithSource:theSource withEvent:event]; } NSLog(@"Type of Event:%@",typeOfEvent); if ([typeOfEvent isEqualToString:@"Hello"]) { event.title = [NSString stringWithFormat:@"%@ Hello",[theData.hello_info objectForKey:@"customer_name"]]; event.location = [NSString stringWithFormat:@"Phone #%@",[theData.hello_info objectForKey:@"customer_phone_number"]]; event.notes = [NSString stringWithFormat:@"Hello Issue: %@",[theData.hello_info objectForKey:@"hello_issue"]]; NSLog(@"Hello"); } event.startDate = startDate; event.endDate = endDate; event.allDay = NO; EKAlarm *alarm = [EKAlarm alarmWithRelativeOffset:-1800]; // Half Hour Before event.alarms = [NSArray arrayWithObject:alarm]; [eventStore saveEvent:event span:EKSpanThisEvent error:nil]; SAFE_PERFORM_WITH_ARG(_delegate, @selector(wasScheduled), nil); } -(void)setupCalendarWithSource:(EKSource *)theSource withEvent:(EKEvent *)event { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; EKCalendar *cal; cal = [EKCalendar calendarWithEventStore:eventStore]; cal.title = @"My Appointments"; cal.source = theSource; [eventStore saveCalendar:cal commit:YES error:nil]; NSLog(@"cal id = %@", cal.calendarIdentifier); NSString *calendar_id = cal.calendarIdentifier; [defaults setObject:calendar_id forKey:@"My Calendar"]; event.calendar = cal; } 

我不知道为什么你会得到这种行为,但我认为,由于禁用iCloud,系统无法对其进行查询,然后排队创build请求,一旦你唤醒iCloud解决(但我假设)。

无论如何,我想到的第一个解决scheme是以这种方式检查iCloud是否活动

 EKSource *defaultSource = [eventStore defaultCalendarForNewEvents].source; if (defaultSource.sourceType == EKSourceTypeCalDAV) NSLog(@"iCloud Enable"); else NSLog(@"iCloud Disable"); 

这样做,你可以保存你的事件到默认的来源,然后保持2日历(本地和云之一)彼此同步…

仍然会提示重新激活iCloud以添加所有本地日历。

另请参阅第二个答案在iOS设备上访问以编程方式创build的日历 (这是我的想法;))

我希望我是有帮助的。

编辑:也许是没有必要创build第二个日历…尝试将EKSourceTypeCalDAV日历的来源更改为EKSourceTypeLocal …不要忘记保存日历提交“是”

编辑2:好的刚刚testing…

替代这个:

 } else { // Create Calendar EKSource *theSource = nil; for (EKSource* src in eventStore.sources) { if ([src.title isEqualToString:@"iCloud"]) { theSource = src; break; } if (src.sourceType == EKSourceTypeLocal && theSource==nil) { theSource = src; break; } } [self setupCalendarWithSource:theSource withEvent:event]; } 

有了这个 …

 } else { // Create Calendar EKSource *theSource = [eventStore defaultCalendarForNewEvents].source; [self setupCalendarWithSource:theSource withEvent:event]; } 

这样你将在正确的来源创build日历(本地如果用户停用iCloud和CalDAV,否则)

然后:

1)当用户select停用iCloud应该离开iPhone上的日历(而不是删除),所以你有本地源的云日历

2)当用户select激活iCloud将合并他的本地日历与云,那里你去!

我希望这个帮助

如果您希望以防弹的方式查找iCloud日历,并在iCloud已禁用的情况下还原到本地日历,请使用以下代码。 我已经包含了一些可能有所帮助的评论:

 for (EKSource *source in eventStore.sources) { //Check for iCloud if (source.sourceType == EKSourceTypeCalDAV && [source.title isEqualToString:@"iCloud"]) { NSLog(@"Found iCloud Service."); //Found iCloud if([source calendarsForEntityType:EKEntityTypeEvent].count>0){ //Check to see if Calendar is enabled on iCloud NSLog(@"iCloud Calendar is Enabled."); //Calendar is Enabled if([self saveEventCalendarWithSource:source]){ return YES; } }else{ NSLog(@"iCloud Calendar is Disabled."); //Calendar is Disabled } } } //If we are here it means that we did not find iCloud Source with iCloud Name. Now trying any CalDAV type to see if we can find it for (EKSource *source in self.reminderStore.sources) { //Check for iCloud if (source.sourceType == EKSourceTypeCalDAV) { [self logData:@"Trying to save calendar in EKSourceTypeCalDAV Service."]; if([self saveEventCalendarWithSource:source]){ return YES; } } } //If we are here it means that we did not find iCloud and that means iCloud is not turned on. Use Local service now. for (EKSource *source in self.reminderStore.sources) { //Look for Local Source if (source.sourceType == EKSourceTypeLocal){ //Found Local Source NSLog(@"Found Local Source."); if([self saveEventCalendarWithSource:source]){ return YES; } } } 

以下是保存日历的代码:

 - (Boolean) saveEventCalendarWithSource:(EKSource *)source{ EKCalendar *Calendar = nil; MyCalendar = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:eventStore]; MyCalendar.title = @"XXX"; MyCalendar.CGColor = [UIColor blueColor].CGColor; MyCalendar.source = source; NSError *err; if([eventStore saveCalendar:MyCalendar commit:YES error:&err]){ if(MyCalendar.calendarIdentifier == nil){ NSLog(@"Could not save Calendar: %@",err); return FALSE; } NSLog(@"Calendar Created. Here's the identifier %@",[MyCalendar calendarIdentifier]); return TRUE; } NSLog(@"Could not create calendar! Reason:%@",err.description); return FALSE; 

}

你的post是一个很大的帮助,我正在努力与完全相同的错误。 谢谢 !

我只做了一些小修改,因为使用defaultCalendarForNewEvents源代码的解决scheme在任何情况下都不起作用:某些源代码不会让您在其中创build新的日历。

我只是检查我的icloud源日历的数量。 如果计数为零,那么日历同步closures,我拿本地来源:

 EKSource* localSource = nil; EKSource* iCloudSource = nil; for (EKSource* source in _eventStore.sources){ if (source.sourceType == EKSourceTypeLocal){ localSource = source; }else if(source.sourceType == EKSourceTypeCalDAV && [source.title isEqualToString:@"iCloud"]){ iCloudSource = source; } } if (iCloudSource && [iCloudSource.calendars count] != 0) { calendar.source = iCloudSource; }else{ calendar.source = localSource; } 
Interesting Posts