iOS EKEvent Store recreating iCloud calendars in a loop, won't save local.
我遇到了一个奇怪的问题 EKEventStore、iCloud 和本地日历。如果启用了 iCloud,则会创建日历并将事件保存到您所期望的日历中。如果 iCloud 已关闭并且您尝试保存事件,则没有任何反应,但是设备会继续每 3-5 秒循环创建 iCloud 日历,直到重新打开 iCloud,然后所有这些日历作为副本涌入 iCloud。我使用的代码几乎与此处多次引用的代码以及 Apples Docs 中的代码完全相同。我完全不明白为什么它不起作用,而且一般来说,关于 EKEventStore 的文档似乎很少。
//????????????????????????????????????????????? ??
#pragma mark – 保存事件
//???????????????????????????????????????????????????
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | -(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,系统无法对其进行查询,然后在唤醒 iCloud 后排队创建请求(但我\\我假设)。
无论如何,我想到的第一个解决方案是以这种方式检查iCloud是否处于活动状态
1 2 3 4 5 6 | EKSource *defaultSource = [eventStore defaultCalendarForNewEvents].source; if (defaultSource.sourceType == EKSourceTypeCalDAV) NSLog(@"iCloud Enable"); else NSLog(@"iCloud Disable"); |
完成后,您可以将您的活动正确保存到默认来源,然后保持 2 个日历(本地日历和云端日历)彼此同步...
仍然会提示重新激活 iCloud 添加所有本地日历。
另请参阅此处的第二个答案在 iOS 设备上访问以编程方式创建的日历(这是我的想法;))
希望我能帮到你。
编辑:也许没有必要创建第二个日历...尝试将日历的来源从 EKSourceTypeCalDAV 更改为 EKSourceTypeLocal ...不要忘记使用 commit "YES"
保存日历
EDIT2:好的,刚刚测试过...
替换为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | } 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]; } |
有了这个...
1 2 3 4 5 6 | } else { // Create Calendar EKSource *theSource = [eventStore defaultCalendarForNewEvents].source; [self setupCalendarWithSource:theSource withEvent:event]; } |
通过这种方式,您将在正确的来源中创建日历(如果用户停用 iCloud 和 CalDAV,则为本地)
然后:
1) 当用户选择停用 iCloud 时,应将日历保留在 iphone 上(而不是删除),以便您在本地源中拥有云日历
2) 当用户选择激活 iCloud 时,会将他的本地日历与云端合并,然后就可以了!!
我希望这会有所帮助
如果您想找到 iCloud 日历并在 iCloud 被禁用时恢复到本地日历,请使用下面的代码。我已经包含了一些可能会有所帮助的评论:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 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; } } } |
这是保存日历的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | - (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; |
}
您的帖子很有帮助,我正在努力解决完全相同的错误。谢谢 !
我只是做了一些小的修改,因为使用 defaultCalendarForNewEvents\\' 源的解决方案并非在所有情况下都有效:某些源不允许您在其中创建新日历。
我只是查看 icloud 源中的日历数量。如果计数为零,则日历同步关闭,我采用本地来源:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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; } |