Question

Can someone help me figure out what I'm doing wrong here. My app is supposed to access the iPhone's various calendars to check on upcoming events. So I need access to "events" in the calendar and also "reminders". When I have the events I store them temporarily in UserDefaults

In my .h file I have stuff like this

@property (nonatomic, strong) EKEventStore *eventStore;
@property (nonatomic, strong) NSMutableArray *calendars;
@property (nonatomic, strong) NSMutableArray *reminders;
@property (nonatomic) BOOL accessToCalendarsGranted;
@property (nonatomic) BOOL accessToRemindersGranted;

and I need to get permission from the user to access these so in the main code I have code like this:

    -(void)requestCalendarAccess
{
    // Prompt the user for access to their Calendar

    [_eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error){
        if (!granted)
        {
            NSLog(@"user has not granted access to calendars!!");
            // Display a message if the user has denied or restricted access to Calendar
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Privacy Warning", nil)
                                                            message:NSLocalizedString(@"Permission was not granted for Calendar", nil)
                                                           delegate:nil
                                                  cancelButtonTitle:NSLocalizedString(@"Dismiss", nil)
                                                  otherButtonTitles:nil];
            [alert show];

            return;
        }

        // Let's ensure that our code will be executed from the main queue
        dispatch_async(dispatch_get_main_queue(), ^{
            // The user has granted access to their Calendar
            [self accessGrantedForCalendar];
        });
    }];
}

which is finished off by the code in accessGrantedForCalendar

_calendars = [[NSUserDefaults standardUserDefaults] objectForKey:kCalendarListKey];

//if we have calendars stored in user defaults, we go and read them
if(!_calendars)
{
    _calendars = [[NSMutableArray alloc] init];
    NSArray *phoneCalendarArray = [_eventStore calendarsForEntityType:EKEntityTypeEvent];

for (EKCalendar *systemCalendar in phoneCalendarArray)
{
    NSMutableDictionary *calendarDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:[systemCalendar title], kCalendarName, [systemCalendar calendarIdentifier], kCalendarIndentifier, [NSNumber numberWithBool:YES], kCalendarWatched,  nil];

    [_calendars addObject:calendarDict];
}

[[NSUserDefaults standardUserDefaults] setObject:_calendars forKey:kCalendarListKey];
[[NSUserDefaults standardUserDefaults] synchronize];

}

And this all works fairly well now. Lots of other code for actually getting events not included here. The problem comes when I try the same approach for reminders:

-(void)requestRemindersAccess
{
    [self.eventStore requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError *error){
        if (granted)
        {
            // Let's ensure that our code will be executed from the main queue
            dispatch_async(dispatch_get_main_queue(), ^{
            // The user has granted access to their Calendar
                [self accessGrantedForReminder];
            });
        }
        else
        {
            NSLog(@"user has not granted access to reminders!!");
            // Display a message if the user has denied or restricted access to Calendar
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Privacy Warning", nil)
                                                            message:NSLocalizedString(@"Permission was not granted for Reminders", nil)
                                                           delegate:nil
                                                  cancelButtonTitle:NSLocalizedString(@"Dismiss", nil)
                                                  otherButtonTitles:nil];
            [alert show];
        }
    }];
}

and the code which finishes this in accessGrantedForReminder:

_reminders = [[NSUserDefaults standardUserDefaults] objectForKey:kRemindersListKey];

//if we don't have reminders stored in user defaults, we go and read them
if(!_reminders || _reminders.count == 0)
{
    _reminders = [[NSMutableArray alloc] init];
    //FOLLOWING LINE HAS PROBLEM FIRST TIME!!!
    NSArray *phoneReminderArray = [_eventStore calendarsForEntityType:EKEntityTypeReminder];

for (EKCalendar *systemCalendar in phoneReminderArray)
{
    NSMutableDictionary *calendarDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:[systemCalendar title], kCalendarName, [systemCalendar calendarIdentifier], kCalendarIndentifier, [NSNumber numberWithBool:YES], kCalendarWatched,  nil];

    [_reminders addObject:calendarDict];
}

[[NSUserDefaults standardUserDefaults] setObject:_reminders forKey:kRemindersListKey];
[[NSUserDefaults standardUserDefaults] synchronize];

}

The line indicated above has a problem - the first time I run the application (i.e. immediately after receiving permission) I see phoneReminderArray has zero objects in it. If I exit the program and run again phoneReminderArray will get one object. It's driving me nuts - why does it only work after I exit the app (while the other calendars Home, Work & Birthdays) all seem to come up right away?

Any ideas anyone?

FYI I looked at this related question and it helped me figure out my initial problems with the first lot of calendar events, but it's not helping for Reminders

Was it helpful?

Solution

The solution is actually very simple. Right before your call to the following line for fetching reminders:

  NSArray *phoneReminderArray = [_eventStore calendarsForEntityType:EKEntityTypeReminder];

Place this line:

[_eventStore reset];

this should fix your problem.

OTHER TIPS

I wasn't able to get it to work after talashar's answer, I also tried the similar refreshSourcesIfNecessary method to no avail.

What did work for me: I had to call this line before asking for the list of reminder calendars:

[_eventStore defaultCalendarForNewReminders];

After that, I was able to get the list of reminder calendars with:

[_eventStore calendarsForEntityType:EKEntityTypeReminder]
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top