Programatically add a reminder to the Reminders app - ios

I'm creating a simple note application and I want to implement Reminders. The user would type a note, tap a button and it would set up a reminder in the Reminders app using the text. Is this possible, and if so, how do I do it? I have seen Apple's documentation on EventKit and EKReminders but it has been no help at all.

From the "Calendars and Reminders Programming Guide"? Specifically "Reading and Writing Reminders"
You can create reminders using the reminderWithEventStore: class method. The title and calendar properties are required. The calendar for a reminder is the list with which it is grouped.
Before you create a reminder, ask for permission:
In the .h:
#interface RemindMeViewController : UIViewController
{
EKEventStore *store;
}
and the .m, when you are going to need access to Reminders:
store = [[EKEventStore alloc] init];
[store requestAccessToEntityType:EKEntityTypeReminder
completion:^(BOOL granted, NSError *error) {
// Handle not being granted permission
}];
To actually add the reminder. This happens asynchronously, so if you try to add a reminder immediately after this, it will fail (crashes the app in my experience).
- (IBAction)addReminder:(id)sender
{
EKReminder *reminder = [EKReminder reminderWithEventStore:store];
[reminder setTitle:#"Buy Bread"];
EKCalendar *defaultReminderList = [store defaultCalendarForNewReminders];
[reminder setCalendar:defaultReminderList];
NSError *error = nil;
BOOL success = [store saveReminder:reminder
commit:YES
error:&error];
if (!success) {
NSLog(#"Error saving reminder: %#", [error localizedDescription]);
}
}

Related

unable to add event using EventKit in iOS app

I am trying to add event in iOS app using Event kit with following code:
EKEventStore *store = [[EKEventStore alloc] init];
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (!granted) { return; }
dispatch_async(dispatch_get_main_queue(), ^{
EKEvent *event = [EKEvent eventWithEventStore:store];
event.title = eventName;
event.startDate = [NSDate dateFromString:[NSString stringWithFormat:#"%# %#",[arrEvent objectAtIndex:1],[arrEvent objectAtIndex:2]] withFormat:#"MM/dd/yyyy HH:mm"];
event.endDate = [NSDate dateFromString:[NSString stringWithFormat:#"%# %#",[arrEvent objectAtIndex:1],[arrEvent objectAtIndex:3]] withFormat:#"MM/dd/yyyy HH:mm"];
[event setCalendar:[store defaultCalendarForNewEvents]];
NSError *err = nil;
[store saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
NSString *savedEventId = event.eventIdentifier; //this is so you can access this event later
NSLog(#"%#",savedEventId);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Event added to calendar" message:nil delegate:self cancelButtonTitle:#"OK" otherButtonTitles:#"View Calendar", nil];
alert.tag = 101;
[alert show];
});
}];
But I am getting granted as false so it doesn't add the event. It is not working in my simulator and device both, even after I reset my simulator. Same code works in another app of mine. Can someone please suggest me what I should do?
Edit: Error is always nil
When app launched for first time, a message asking for permissions will be shown to the user, and app will be able to access the calendar if only the user granted permission. In your case you have declined permission for calendar.
For fixing this issue, Go to Settings -> -> Allow to access calendar = YES.
Seems like you're requesting to get the access every time. You should better check the authorisation status first and if it's not determined, only then request for the authorisation. First check this using "authorizationStatusForEntityType" and create a new method to save the event, not inside "requestAccessToEntityType".

How to set a prompt for second time when user has clicked Don't allow for permissions the first time?

I want to add a prompt when user access the calendar second time, when initially user has clicked Don't Allow for the first access permissions for calendar.
// For iOS 6.0 and later
EKEventStore *_eventStore [[EKEventStore alloc] init];
[_eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
// handle access here
}];
EKEventStore *_reminderStore [[EKEventStore alloc] init];
[_reminderStore requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError *error) {
// handle access here
}];
This piece of code is for the first time when user is being asked for the permissions, can anyone please tell me, what to do when user has clicked Don't allow after this ?
You can put the second request inside the first request's block.
So it would look like this:
// For iOS 6.0 and later
EKEventStore *_eventStore [[EKEventStore alloc] init];
[_eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (granted) {
[_eventStore requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError *error) {
// handle access here
}];
}
}];
Also keep in mind that initializing an EKEventStore is expensive. Try to only use one instance of it. That information and more can be found in the documentation

Opening Reminder application within iOS application?

Is it possible to use iOS Reminder Built in Application within the App I develop?
I dont want to use OPEN URL concept, because it will quit my app an open Reminder App?
Can I please any Custom Reminder App deveoped by iOS SDk , which will create Reminder
in iOS's Reminder Application
There is a reminders API that allows you to create and retrieve reminders.
You'll first have to ask for user permission to do so:
EKEventStore *store = [[EKEventStore alloc] initWithAccessToEntityTypes:EKEntityMaskReminder];
[store requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError *error) {
if (granted) {
[self createReminder:store];
}
else {
// :(
}
}];
To create a reminder you could:
- (void)createReminder:(EKEventStore *)store {
//Create a reminder instance
EKReminder *aReminder = [EKReminder reminderWithEventStore:store];
// Set the properties
aReminder.title = #"Remember to do X";
...
// Then save the reminder to the store
NSError *error = nil;
[store saveReminder:aReminder commit:YES error:&error];
// Be responsible
if (error) {
[self rememberToHandleYourErrors:error];
}
}

iOS - Delete Recurring EKEvent, event appears again

I have a recurring event in calendar. I'm delete a single event using this code [store removeEvent:event span:EKSpanThisEvent commit:YES error:&errorThis]; and this methods returns true but the event is not deleted from the calendar.
On EKCalendarItem Class reference using the property calendarItemExternalIdentifier you find this
Recurring event identifiers are the same for all occurrences. If you wish to differentiate between occurrences, you may want to use the start date
So you want delete only a recurrence you have to do something like this:
NSPredicate *predicate = [eventStore predicateForEventsWithStartDate:startDate endDate:endDate calendars:calendars];
NSArray *theEvents = [eventStore eventsMatchingPredicate:predicate];
NSString *recurrenceEventIdentifier;
for(EKEvent * theEvent in theEvents)
{
if([theEvent.eventIdentifier isEqualToString: recurrenceEventIdentifier]
&& ![eventStore removeEvent:theEvent span:EKSpanThisEvent error:&error])
{
NSLog(#"Error in removing event: %#",error);
}
}
Your method instead, deletes only the first occurrence. If you want delete all recurring events just change "span" parameter in EKSpanFutureEvents.
EDIT: Now only deletes the matching recurrent event, not everything.
Please make sure you have only one instance of EKEventStore in singleton pattern in your app :
static EKEventStore *eventStore = nil;
+ (EKEventStore *)getEventStoreInstance
{
if (eventStore == nil){
#synchronized(self){
if (eventStore == nil){
eventStore = [[EKEventStore alloc] init];
}
}
}
return(eventStore);
}

calendarsForEntityType:EKEntityTypeReminder is empty first time, works subsequently

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
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.
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]

Resources