Question

I am simply wanting to add an event to the device's calendar.

I'm using:

 __weak ProgramViewController *weakSelf = self;

 EKEventStore *store = [[EKEventStore alloc] init];

    [store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error)
     {
         if (error)
              NSLog(@"EKEventStore error = %@", error);

         if (granted)
         {
             NSLog(@"EKEvent *event ");

             EKEvent *event = [EKEvent eventWithEventStore:store];
             event.title = weakSelf.program.title;
             event.location = weakSelf.program.locationPublic;
             event.startDate = weakSelf.program.startTime;
             event.endDate = weakSelf.program.endTime;
             [event setCalendar:[store defaultCalendarForNewEvents]];
             NSError *err = nil;
             [store saveEvent:event span:EKSpanThisEvent commit:YES error:&err];

             if (err)
             {
                 UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Calendar Error" message:err.localizedDescription delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
                 [alertView show];
             }
             else
             {
                 UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Added" message:@"Calendar event added." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
                 [alertView show];
             }
         }
     }];

and in iOS 6 it can take 6/7 seconds (iPhone 4) and on iOS 7 (on an iPhone 5S) it takes ~10 seconds. Is this normal behaviour? If not what am I doing wrong?

Was it helpful?

Solution

I had the same issue. Thanks to Jasper's answer, I got thinking about queues. Try this:

    if (!err)
    {
        dispatch_async(dispatch_get_main_queue(),
        ^{
            [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"event added", nil) message:nil delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", nil) otherButtonTitles:nil] show];
        });
    }

Here's why this is needed (see emphasis)

Discussion

In iOS 6 and later, requesting access to an event store asynchronously prompts your users for permission to use their data. The user is only prompted the first time your app requests access to an entity type; any subsequent instantiations of EKEventStore uses existing permissions. When the user taps to grant or deny access, the completion handler will be called on an arbitrary queue. Your app is not blocked while the user decides to grant or deny permission.

Since UIAlertView is UIKit, and UIKit always requires the main thread, any other arbitrary thread will crash or lead to unpredictable behaviour.

https://developer.apple.com/library/ios/documentation/EventKit/Reference/EKEventStoreClassRef/Reference/Reference.html

OTHER TIPS

According to the docs: "An EKEventStore object requires a relatively large amount of time to initialize and release." . . so you should dispatch this on a background queue.

Also, oddly, it takes longer on the main queue than the background queue - not sure why this is!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top