问题
I have an app I am trying to help get out the door. This code was originally written with iOS5 in mind by another team. I added the requestAccessToEntityType:completion: call which runs successfully. However, after being granted access, I get no sources / defaultCalendar or calendars based on entity. And I cannot create a new calendar.
When calling defaultCalendarForNewEvents I get this error
Error Domain=EKCADErrorDomain Code=1013 "The operation couldn’t be completed. (EKCADErrorDomain error 1013.)"
and the result is nil.
If I back out of the viewController trying to do this and go back in, it all works fine. If, after getting the alert about no source, I keep trying (without backing out the viewController), it repeatedly fails.
I want to stress, that the authorization call works (the user is asked for access to calendars and gives it, and later calls to confirm authorization pass). All the other questions I have found that are similar have that as the solution -- making sure you requestAccessToEntityType
[eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (granted)
{
//[self performSelectorOnMainThread:@selector(doScheduleActivity:) withObject:activity waitUntilDone:YES];
dispatch_async(dispatch_get_main_queue(), ^{
[self doScheduleActivity:activity];
});
}
else
{ // probably should force the main thread
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"Calendar Access Required" message:@"In order to schedule activities, APP needs access to your Calendar. You can change this in your device Settings." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[av show];
});
}
}] ;
granted
comes back true and the [self doScheduleActivity: gets called. The following code is a function called at the very beginning of that routine and where the failures are.
EKCalendar *saCalendar;
EKSource *source;
NSError *error;
UIAlertView *alert;
LogDebug(@"eventStore defaultCalendar %@", [eventStore defaultCalendarForNewEvents]);
// validate access to calendar prior to segueing
if ([EKEventStore respondsToSelector:@selector(authorizationStatusForEntityType:)])
{
switch([EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent])
{
case EKAuthorizationStatusAuthorized:
break;
case EKAuthorizationStatusNotDetermined:
{
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:SA_ALERT_CAPTION_CALENDAR_ACCESS_NOT_DETERMINED message:SA_ALERT_BODY_CALENDAR_ACCESS_NOT_DETERMINED delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
[alert show];
});
return false;
}
case EKAuthorizationStatusDenied:
{
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:SA_ALERT_CAPTION_CALENDAR_ACCESS_DENIED message:SA_ALERT_BODY_CALENDAR_ACCESS_DENIED delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
[alert show];
});
return false;
}
case EKAuthorizationStatusRestricted:
{
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:SA_ALERT_CAPTION_CALENDAR_ACCESS_RESTRICTED message:SA_ALERT_BODY_CALENDAR_ACCESS_RESTRICTED delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
[alert show];
});
return false;
}
default:
break;
}
}
// search for application specifc calendar..
saCalendar = nil;
for(EKCalendar *calendar in [eventStore calendarsForEntityType:EKEntityTypeEvent])
{
if([calendar.title isEqualToString:SA_ACTIVITIES_CALENDAR_TITLE])
{
saCalendar = calendar;
break;
}
}
// ..and create from scratch if nonexistent
if(nil == saCalendar)
{
// find local source to hook up new calendar to
for(source in [eventStore sources])
{
if(source.sourceType == EKSourceTypeLocal)
{
break;
}
}
// if could not find local source type, something is wrong
if( source == nil || source.sourceType != EKSourceTypeLocal)
{
alert = [[UIAlertView alloc] initWithTitle:SA_ALERT_CAPTION_CALENDAR_ERROR_NO_SOURCE message:SA_ALERT_BODY_CALENDAR_ERROR delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil];
[alert show];
return false;
}
// create calendar for applcation, name it, color it and assign source
saCalendar = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:eventStore];
[saCalendar setSource:source];
[saCalendar setTitle:SA_ACTIVITIES_CALENDAR_TITLE];
[saCalendar setCGColor:[[UIColor yellowColor] CGColor]];
// create immediately
error = nil;
if(![eventStore saveCalendar:saCalendar commit:true error:&error])
{
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:SA_ALERT_CAPTION_CALENDAR_ERROR_CANT_SAVE message:SA_ALERT_BODY_CALENDAR_ERROR delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil];
[alert show];
});
return false;
}
}
return true;
Everything comes back nil though it was authorized and the check in [EKEventStore authorizationStatusForEntity:EKEntityType
returns EKAuthorizationStatusAuthorized
After I get a failure here, if I back out of this view controller and go back in, it works. This only happens the first time when the system asks the user for calendar access and they reply OK.
Thanks for any insight. I've been stepping through the debugger, and also doing printf type debugging to avoid any sort of timing issues, etc. and see nothing contrary to the event stuff I have looked up on the Apple site.
My target device is 6.1.3 iPhone 5
回答1:
OK, it turns out there was a small line of code in a viewDidLoad that was before the [eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error
code and that tried to access the eventStore. It was superfluous and did not need to be happening and I had not noticed it. Once I removed this code the stuff now works, so it does go back to needing to authorize, as even after authorization, the eventStore was already "bad" due to this previous access.
回答2:
The problem can also be solved by recreating the EKEventStore instance in the callback once access is granted.
来源:https://stackoverflow.com/questions/17976831/ios-ekeventstore-sources-defaultcalendarfornewevents-calendarsforentitytype