Building iRemember – shopping list app, part 2

iRemember
Let’s continue building our iRemember application.

We’ve created methods for querying calendars and reminders. Now it is time to create methods that add and delete reminders.

But before, we need to take care of requesting access to reminders. Our manager has read-only property accessGranted, and methods to request access (sync and async).

-(BOOL)accessGranted
{
    return ([EKEventStore authorizationStatusForEntityType:EKEntityTypeReminder] == EKAuthorizationStatusAuthorized);
}

-(void)requestAccess
{
    if (!self.accessGranted)
    {
        [self.store requestAccessToEntityType:EKEntityTypeReminder
                                   completion:NULL];
    }
}

-(void)requestAccessAndWait
{
    if (!self.accessGranted)
    {
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        
        [self.store requestAccessToEntityType:EKEntityTypeReminder
                                   completion:^(BOOL granted, NSError *error) {
                                       dispatch_semaphore_signal(semaphore);
                                   }];
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    }
}

accessGranted property is actually calling EKEventStore class method. In case when access is not yet granted, we can use -requestAccess or -requestAccessAndWait methods to ask user (user will be asked only once). If user denies access, we should respond to that with UI changes (for example, we can show special view controller describing why do we insist on having access to reminders).
We’re not trying to request access, if it is already granted. -requestAccessAndWait method uses GCD semaphores to make synchronous method out of asynchronous.

Now it’s time to implement code to create and delete reminders. These methods will have asynchronous callbacks, since these operations are also time-consuming.

typedef void (^IRReminderAddCompletionBlock)(EKReminder *reminder);

-(void)addReminderWithTitle:(NSString*)title 
   inCalendarWithIdentifier:(NSString*)calendarIdentifier 
                 completion:(IRReminderAddCompletionBlock)completionBlock
{
    if (self.accessGranted)
    {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            EKReminder *reminder = [EKReminder reminderWithEventStore:self.store];
            reminder.calendar = [self.store calendarWithIdentifier:calendarIdentifier];
            reminder.title = title;
            
            NSError __autoreleasing *error;
            
            if (![self.store saveReminder:reminder 
                                   commit:YES 
                                    error:&error])
            {
                // log error, take corrective actions, if possible
            }

            if (completionBlock)
            {
                completionBlock(reminder);
            }
        });
    }
    else if (completionBlock)
    {
        completionBlock(nil);
    }
}

First, we check that access to reminders is granted. Then we’re trying to create and save EKReminder object.
completionBlock is called (actually, method allows to pass NULL as completionBlock, so we need to verify parameter), created object is passed as a parameter to block, or nil in case of problems.
Standard methods are synchronous, so we’re using GCD to run it in a separate thread.

Removing reminder is similar

typedef void (^IRReminderOperationCompletionBlock)(BOOL result);

-(void)removeReminder:(EKReminder*)reminder 
       withCompletion:(IRReminderOperationCompletionBlock)completionBlock
{
    if (self.accessGranted)
    {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSError __autoreleasing *error;
            
            BOOL result = [self.store removeReminder:reminder 
                                              commit:YES 
                                               error:&error];
            if (!result)
            {
                // log error, take corrective actions, if possible
            }

            if (completionBlock)
            {
                completionBlock(result);
            }
        });
    }
    else if (completionBlock)
    {
        completionBlock(NO);
    }
}

Again we use GCD to run code in background queue, and use completionBlock to report results.

This is it for today. Next time we’ll start working on UI part of our application.

For more information on EventKit, consult Apple documentation – Calendar and Reminders Programming Guide, Event Kit Framework Reference.
Source code for this tutorial is available on GitHub.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s