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);
}
Related
I am trying to remove a EKCalendar that I have created inside my iOS app using the following method.
- (void)DeleteCalendar
{
EKEventStore *eventStore = [[EKEventStore alloc] init];
EKEntityType type = EKEntityTypeEvent;
NSArray *calendars = [eventStore calendarsForEntityType:type];
for (EKCalendar *thisCalendar in calendars){
NSLog(#"Calendar: %#", thisCalendar.title);
if ([thisCalendar.title isEqualToString:[NSString stringWithFormat:#"%#%#",CALENDARPREFIX, _currentCName]]) {
NSError *err;
[eventStore removeCalendar:thisCalendar commit:YES error:&err];
if (!err) {
NSLog(#"deleted %#", thisCalendar.title);
} else {
NSLog(#"%#", err.localizedDescription);
}
}
}
}
However when I run this method I get the following error from the last else statement.
That event does not belong to that event store
I have read that there is a bug in removeCalendar: however was hoping someone else may have experienced this and can help me fix the issue.
In my app, I create events in an EKCalendar. I fetch the events online, and in order to refresh the events, I want to first delete the calendar (if it exists), recreate it, and then put the new events in there.
To instantiate the calendar I use
- (EKCalendar *)calendar {
if (!_calendar) {
NSArray *calendars = [self.store calendarsForEntityType:EKEntityTypeEvent];
NSString *calendarTitle = #"MyCalendar";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"title matches %#", calendarTitle];
NSArray *filtered = [calendars filteredArrayUsingPredicate:predicate];
if ([filtered count]) {
_calendar = [filtered firstObject];
} else {
_calendar = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:self.store];
_calendar.title = calendarTitle;
_calendar.source = self.store.defaultCalendarForNewEvents.source;
NSError *calendarErr = nil;
BOOL calendarSuccess = [self.store saveCalendar:_calendar commit:YES error:&calendarErr];
if (!calendarSuccess) {
NSLog(#"Calendar Error = %#", [calendarErr localizedDescription]);
}
}
}
return _calendar;
}
To delete the calendar, I use
-(IBAction)deleteCalendar{
NSError *error = nil;
[self.store removeCalendar:_calendar commit:YES error:&error];
}
Both methods work fine individually.
So, when I start the creation of events, I do the following:
[self deleteCalendar];//delete calendar and its events, in case it already exists
[self calendar];//create calendar
[self importEvents];//put events in calendar
Now, what I observe is the following:
On the first run of the app
a calendar is created
events are imported. (This is expected, and works just fine)
While the app is running, I trigger the above methods again with a button. With the following, for me puzzling, result:
the calendar is deleted (expected result)
NO calendar is created (WHY? that is my main question).The "if (!_calendar)" part of the method is considered FALSE, and nothing is executed.
The 'importEvents' method runs through its regular hoopla, without any apparent errors, although I would expect something like a 'no source' error.
Please advise.
UPDATE:
This could be an indicator of what is happening, but I still don't get it:
After a while, the events appear in a different calendar, i.e. not the calendar called 'myCalendar', but another, iCloud based calendar, apparently the one that at that point is the defaultCalendarForNewEvents. However, that also doesn't make any sense to me.
OK, so, what is happening:
I have deleted the Calendar from the store, effectively, but a reference to that calendar actually was still hanging around in my app.
I solved it as follows:
-(IBAction)deleteCalendar:(id)sender{
NSError *error = nil;
if(_calendar){
[self.store removeCalendar:_calendar commit:YES error:&error];
}
_calendar = nil;
}
I hope this is useful to someone
I've developed an app that uses calendar using the eventkit.
The user can push a button and delete a specific event. Everything works just fine, except when it comes to recurrent events.
If the user itself created the recurrent events, it works as expected, the single event is deleted and the rest remains in calendar. But if the recurrent events is created by other and accepted by user and then try to delete one specific of those events, they all disappear from calendar. Why?
In this case iPad only uses one Exchange calendar, can the problem be Exchange specific?
/* Get the Exchange Calendar */
EKEventStore* store = [[EKEventStore alloc] init];
NSError* error = nil;
NSMutableArray* calendars = [[store calendarsForEntityType:EKEntityTypeEvent] mutableCopy];
NSMutableArray* cals = [[NSMutableArray alloc] init];
for (EKCalendar *cal in calendars) {
if (cal.type == EKCalendarTypeExchange) {
[cals addObject:cal];
break;
}
}
/* get the correct event, get Events with startDate & endDate and differ with eventId */
// (tappedEvent = event to remove)
NSPredicate *predicate = [store predicateForEventsWithStartDate:[tappedEvent valueForKey:#"from"] endDate:[tappedEvent valueForKey:#"to"] calendars:cals];
NSArray *theEvents=[store eventsMatchingPredicate:predicate];
NSString *recurrenceEventIdentifier = [tappedEvent valueForKey:#"appID"];
for(EKEvent * theEvent in theEvents){
if([theEvent.eventIdentifier isEqualToString: recurrenceEventIdentifier] && ![store removeEvent:theEvent span:EKSpanThisEvent error:&error]){
NSLog(#"Error in removing event: %#",error);
}
}
[store commit:&error];
if(error){
...
}
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]);
}
}
I am trying to delete an event from the Calendar on user request. This is what I've come up with:
// Deleting Event
EKEventStore *eventStore = [[EKEventStore alloc] init];
EKEvent *event = [EKEvent eventWithEventStore:eventStore];
event.title = appDelegate.title1;
event.startDate = appDelegate.recAddDate;
event.endDate = appDelegate.currentDateName;
[event setCalendar:[eventStore defaultCalendarForNewEvents]];
NSError *err;
[eventStore removeEvent:event span:EKSpanThisEvent error:&err];
Below is the function I'm calling to remove the event from the event array. Items array is used to fetch events from iPhone calendar
- (BOOL)removeEvent:(EKEvent *)event span:(EKSpan)span error:(NSError **)error{
VoiceRecorderAppDelegate *appDelegate = (VoiceRecorderAppDelegate *)[[UIApplication sharedApplication] delegate];
[items removeObjectAtIndex:appDelegate.objectindexpath];
}
Firstly, save the eventId for the event while adding/saving events to the calendar.
[eventStore saveEvent:event span:EKSpanThisEvent error:&err];
NSString* str = [[NSString alloc] initWithFormat:#"%#", event.eventIdentifier];
[arrayofEventId addObject:str];
and then identify the event you want to remove ande then remove that event.
EKEventStore* store = [[EKEventStore alloc] init];
EKEvent* eventToRemove = [store eventWithIdentifier:[arrayofEventId objectAtIndex:i]];
if (eventToRemove != nil) {
NSError* error = nil;
[store removeEvent:eventToRemove span:EKSpanThisEvent error:&error];
}
Also don't forget to remove that event from arrayofEventId as well.
You can achieve this in the following ways:
By creating an NSpredicate using the date range withing which you
want to delete events, 86400 being the duration of a day in events, in
this piece of code I am deleting month old events. I am using a
dispatch queue, as the no. of events fetched may be large, and to keep the UI free.
First Create the event store and check access(access check required only iOS6 onwards):
- (void)addEventsToCalendar {
EKEventStore *eventStore = [[EKEventStore alloc] init];
if ([eventStore respondsToSelector:#selector(requestAccessToEntityType:completion:)]) {
//implementation for devices running OS version iOS 6.0 onwards.
[eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (granted) {
[self removeEventsFromStore:eventStore];
} else {
//perform for No Access using Error
}];
} else {
//implementation for devices running OS version lower than iOS 6.0.
[self removeEventsFromStore:eventStore];
}
}
Then remove events from the store:
- (void)removeEventsFromStore:(EKEventStore*)eventStore {
NSDate *startDate = [NSDate dateWithTimeIntervalSinceNow:-30 * 86400];
NSDate *endDate = [NSDate date];
dispatch_queue_t queue = dispatch_queue_create("com.arc.calendar", NULL);
dispatch_async(queue, ^{
NSArray *calendarArray = [NSArray arrayWithObject:[PWCCalendar getCalendarForEventStore:eventStore]];
NSPredicate *predicate = [eventStore predicateForEventsWithStartDate:startDate endDate:[NSDate dateWithTimeInterval:ONE_DAY_DURATION sinceDate:endDate] calendars:calendarArray];
NSArray *eventArray = [eventStore eventsMatchingPredicate:predicate];
for (EKEvent *event in eventArray) {
[eventStore removeEvent:event span:EKSpanThisEvent commit:YES error:NULL];
}
dispatch_async(dispatch_get_main_queue(), ^{
//Get the main Queue and perform UPdates
});
});
}
This is the Long way, use it to delete events in bulk. But if you need to delete only One event, then save the events identifier to `NSUserDefaults(after generating the event)
[eventStore saveEvent:event span:EKSpanThisEvent commit:YES error:NULL];
[[NSUserDefaults standardUserDefaults] setObject:[event eventIdentifier] forKey:#"Event ID"];
and then fetch it back while removing using
[eventStore eventWithIdentifier:#"Event ID"];
and then remove it from the store using
[eventStore removeEvent:event span:EKSpanThisEvent commit:YES error:NULL];
For more clarifications on the other methods to fetch events or calendar, pelase refer to EventStore docs: http://developer.apple.com/library/ios/#documentation/EventKit/Reference/EKEventStoreClassRef/Reference/Reference.html#//apple_ref/doc/uid/TP40009567 or to the Calendar and Reminder Programming guide: http://developer.apple.com/library/ios/#documentation/DataManagement/Conceptual/EventKitProgGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009765