iOS - How to create recurring calendar events with exclusion occurrences (date)? - ios

I'm trying to create a recurrent event into calendar through JSON API, but with exclusion occurences (/date) I don't know how to do it. I think i create a recurrent event, then I delete occurences.
update:
For example, the event repeats every weekend. However, I removed some of the weekends from the time line, creating an exception to a recurrence rule.
How can I get these excluded dates through the API?
my code:
1. CreateEvent from api json:
NSDictionary *dicEvent = [self.arrayEvents objectAtIndex:index];
EKEventStore *eventStore = [[EKEventStore alloc] init];
EKEvent *event = [EKEvent eventWithEventStore:eventStore];
event.title = [dicEvent objectForKey:#"RecurrenceRule"];
[event setCalendar:[eventStore defaultCalendarForNewEvents]];
event.startDate = [dicEvent objectForKey:#"startDate"];
event.endDate = [dicEvent objectForKey:#"endDate"];
EKSpan span = EKSpanFutureEvents;
[self.eventStore saveEvent:self.savedEvent span:span commit:YES error:&error];
2. then with exclusion occurrences, I think I delete occurences.
EventStore *eventStore = [[EKEventStore alloc] init];
NSPredicate *predicate = [eventStore predicateForEventsWithStartDate:startDate endDate:endDate calendars:calendars];
NSArray *results = [eventStore eventsMatchingPredicate:predicate];
for (int i = 0; i < results.count; i++) {
EKEvent *event = [results objectAtIndex:i]
if ([event.occurencesIdentifier isEqualToString: eventoccurencesIdentifier]) {
// delete occurencesIdentifier
break;
}
Please help me where I had gone wrong.
Thanks!

Related

EKEventStore search event with title NSPredicate

I have requirement to search events added to iOS calendar with title OR notes. I like to search events with [NSPredicate predicateWithFormat:#"title like 'Callback'"].
When googled I got predicateForEventsWithStartDate only. How can we fetch/search events with title OR notes in iOS.
You need 2 predicates to do this
Here a commented example :
// you init your store event
EKEventStore *store = [[EKEventStore alloc] init];
//you get the list of events
NSPredicate *datePredicate = [store predicateForEventsWithStartDate:[[NSDate date] dateByAddingTimeInterval: -86400.0] //yesterday
endDate:[NSDate date] //today
calendars:nil];
//this will return a list of EKEvent
NSArray<EKEvent *> *events = [store eventsMatchingPredicate:datePredicate];
//you create a second predicate to test on title or wethever you want
NSPredicate *textPredicate = [NSPredicate predicateWithFormat:#"title like 'Callback'"];
//here you will get the events with title like Callback
NSArray<EKEvent *> *results = [events filteredArrayUsingPredicate:textPredicate];

Check if Event exists on Calendar

I'm having trouble verifying if an event already exists on the user's calendar. I need to check this to determine if I should add it or not, so that I don't create duplicate calendar entries. Right now, I create a duplicate entry every time I run the code.
First, here is how I am creating the calendar entry:
+ (NSString *) addEventToCalenderWithDate : (NSDate *) eventDate
eventTitle : (NSString *) eventTitle
eventLocation : (NSString *) eventLocation
allDayEvent : (BOOL) isAllDay
{
EKEventStore *store = [[EKEventStore alloc] init];
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (!granted) {
returnValue = #"calendar error";
}
else if ([self eventExists:dateAndTime eventTitle:eventTitle allDayEvent:isAllDay]) {
returnValue = #"duplicate";
}
else {
EKEvent *event = [EKEvent eventWithEventStore:store];
event.title = eventTitle;
event.startDate = dateAndTime;
if (eventTimeString == (id)[NSNull null] || eventTimeString.length == 0 || isAllDay) {
event.allDay = YES;
event.endDate = dateAndTime;
} else {
event.endDate = [event.startDate dateByAddingTimeInterval:60*60]; //set 1 hour meeting
}
event.location = eventLocation;
[event setCalendar:[store defaultCalendarForNewEvents]];
NSError *err = nil;
[store saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
returnValue = #"success";
}
}];
return returnValue;
}
This sets the event correctly. However, if I run it again, I expect that the else if clause will return YES and no new entry will be created. However, it always returns NO and I create a new calendar entry with each execution. Here is that method:
+ (BOOL) eventExists : (NSDate *) date
eventTitle : (NSString *) eventTitle
allDayEvent : (BOOL) isAllDay
{
EKEventStore *store = [[EKEventStore alloc] init];
NSPredicate *predicateForEventOnDate = [[NSPredicate alloc] init];
if (isAllDay)
predicateForEventOnDate = [store predicateForEventsWithStartDate:date endDate:date calendars:nil]; // nil will search through all calendars
else
predicateForEventOnDate = [store predicateForEventsWithStartDate:date endDate:[date dateByAddingTimeInterval:60*60] calendars:nil]; // nil will search through all calendars
NSArray *eventOnDate = [store eventsMatchingPredicate:predicateForEventOnDate];
NSLog(#"eventOnDate: %#", eventOnDate);
BOOL eventExists = NO;
for (EKEvent *eventToCheck in eventOnDate) {
if ([eventToCheck.title isEqualToString:eventTitle]) {
eventExists = YES;
}
}
return eventExists;
}
As I step through this method, I notice that the NSArray called eventOnDate is nil (the EKEventStore is not nil). I don't know if this means that it simply did not find any matching events or if something else is going on.
What am I doing wrong that won't allow this to identify existing events on the calendar? Thank you!
The problem appears to be with the date range you have selected for your predicate.
predicateForEventOnDate = [store predicateForEventsWithStartDate:date endDate:date calendars:nil];
This will look for events within a "0" second range because the start and end date of your predicate query is identical.
predicateForEventOnDate = [store predicateForEventsWithStartDate:date endDate:[date dateByAddingTimeInterval:60*60] calendars:nil];
This will only look for events that lie within an hour of the date provided.
NSCalendar *const calendar = NSCalendar.currentCalendar;
NSCalendarUnit const preservedComponents = (NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay);
//strip away hours, minutes and seconds to find date - at start of day
NSDateComponents *startComponents = [calendar components:preservedComponents fromDate:self.date];
//set finished date to 1 full day later
NSDateComponents *offset = [[NSDateComponents alloc] init];
[offset setDay:1];
NSDate *start = [calendar dateFromComponents:startComponents];
NSDate *finish = [calendar dateByAddingComponents:offset toDate:self.date options:0];
NSPredicate *predicateForEventOnDate = [[NSPredicate alloc] init];
if (isAllDay)
predicateForEventOnDate = [store predicateForEventsWithStartDate:start endDate:finish calendars:nil];
NSArray *eventOnDate = [store eventsMatchingPredicate:predicateForEventOnDate];
This will produce an array that covers events for the full day from start to finish.

Add location to EKEvent IOS Calendar

How to add the location not just NSString but with latitude and longitude ,so it shows a map too in the Calendar?
<EKCalendarItem>
https://developer.apple.com/LIBRARY/ios/documentation/EventKit/Reference/EKCalendarItemClassRef/index.html#//apple_ref/occ/instp/EKCalendarItem/location
#property(nonatomic, copy) NSString *location;
Code :
EKEventStore *store = [[EKEventStore alloc] init];
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (!granted) { return; }
EKEvent *event = [EKEvent eventWithEventStore:store];
event.title = #"Event Title";
event.startDate = [NSDate date]; //today
event.endDate = [event.startDate dateByAddingTimeInterval:60*60]; //set 1 hour meeting
event.notes=#"Note";
event.location=#"Eiffel Tower,Paris"; //how do i add Lat & long / CLLocation?
event.URL=[NSURL URLWithString:shareUrl];
[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
}];
The property structuredLocation is available on iOS 9, though EKEvent documentation doesn't mention it (Update: it's finally here) , but structuredLocation does exist in EKEvent public header file, and you can check it inside Xcode. No need to use KVC to set it after iOS 9.
Swift version as follows:
let location = CLLocation(latitude: 25.0340, longitude: 121.5645)
let structuredLocation = EKStructuredLocation(title: placeName) // same title with ekEvent.location
structuredLocation.geoLocation = location
ekEvent.structuredLocation = structuredLocation
It's pretty bizarre that there is no documentation for this, but this is how you add a geoLocation to a calendar event.
EKStructuredLocation* structuredLocation = [EKStructuredLocation locationWithTitle:#"Location"]; // locationWithTitle has the same behavior as event.location
CLLocation* location = [[CLLocation alloc] initWithLatitude:0.0 longitude:0.0];
structuredLocation.geoLocation = location;
[event setValue:structuredLocation forKey:#"structuredLocation"];
You might be able to use setValue:ForKey: on the EKEvent after creating a EKStructuredLocation, the key is 'structuredLocation'

EventKit - multiple methods named 'location'

I am trying to list out the Name, Location, and Notes from calendar events. Reading and writing the Name and Notes work as expected but I run into problems with the Location field.
Specifically, the following line "meetingLocation = [element location];" produces the error
"Multiple methods named 'location' found with mismatched result, parameter type or attributes."
What is wrong here? Code is included below.
-(IBAction)reloadEvents:(id)sender {
NSString *meetingName;
NSString *meetingLocation;
NSString *meetingNotes;
// Define a range of event dates we want to display
NSDate *startDate = [NSDate dateWithTimeIntervalSinceNow:(-1*60*60*.5)]; // .5 hour in the past
NSDate *endDate = [NSDate dateWithTimeIntervalSinceNow:(60*60*24*1)]; // 1 day from now
//NSDate *endDate = [NSDate dateWithTimeIntervalSinceNow:(60*60*24*7)]; // 7 days from now
// Create a predicate to search all celndars with our date range using the start date/time of the event
NSPredicate *predicate = [self.eventStore predicateForEventsWithStartDate:startDate endDate:endDate calendars:nil];
// Query the event store using the predicate.
NSArray *results = [self.eventStore eventsMatchingPredicate:predicate];
// Convert the results to a mutable array and store so we can implement swipe to delete
//NSMutableArray *events = [[NSMutableArray alloc] initWithArray:results];
//self.events = events;
NSEnumerator * enumerator = [results objectEnumerator];
id element;
while(element = [enumerator nextObject])
{
// Set the meeting name
meetingName = [element title];
NSLog(#"Name=%#",meetingName);
// Set the meeting location
meetingLocation = [element location];
NSLog(#"Location=%#",meetingLocation);
// Set the meeting notes
meetingNotes = [element notes];
NSLog(#"Notes=%#",meetingNotes);
}
}
Try like this
while(element = [enumerator nextObject])
{
EKEvent *event = element;
meetingName = event.location;
}
Similar problem converting some old iOS 5 to iOS7:
if ([[thisEvent.recurrenceRules objectAtIndex:i] frequency] == EKRecurrenceFrequencyDaily ){
resulted in
Multiple methods names "frequency" found with mismatched result.
Resolved by typecasting and then doing the if statement
EKRecurrenceRule *thisRecurranceRule = (EKRecurrenceRule *)[thisEvent.recurrenceRules objectAtIndex:i] ;
if ([thisRecurranceRule frequency] == EKRecurrenceFrequencyDaily ){

EKEvent AddAlarm Not Working

[Fixed] (Kind of)
Seems you can't have an alarm at the end of an event. I wanted the event to appear spanning x number of days in the calendar, then an alarm to signal when it's due to end. Seems that's not possible. Can only have alarms before the event begins. Silly apple :(
I can't seem to get alarms to save when adding new events. Here's the code...
I want the alarm to sound at the time the event occurs, I thought maybe the all-day option was messing it up but it doesn't save regardless.
Here's the code...
EKEventStore *store = [[EKEventStore alloc] init];
EKEvent *event = [EKEvent eventWithEventStore:store];
event.title = title;
event.startDate = [global main].Entry.WithdrawalDate;
event.endDate = [global main].Entry.WithdrawalDate;
//event.allDay = YES;
event.availability = EKEventAvailabilityFree;
event.location = [global main].Holding.Name;
event.notes = [self compileNotes];
//Tried settings the array and adding to it, neither works
//NSArray *arrAlarm = [NSArray arrayWithObject:[EKAlarm alarmWithAbsoluteDate:[global main].Entry.WithdrawalDate]];
//event.alarms= arrAlarm;
EKAlarm * alarm = [EKAlarm alarmWithAbsoluteDate:[global main].Entry.WithdrawalDate];
[event addAlarm:alarm];
[event setCalendar:[store defaultCalendarForNewEvents]];
NSError *err;
saved = [store saveEvent:event span:EKSpanThisEvent commit:YES error:&err];

Resources