EKEvent AddAlarm Not Working - ios

[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];

Related

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

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!

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'

Creating reminders with complex rules in ios

I want to create a repeating reminder with a complex rule i.e
reminders will have a start date and end date.
reminders will repeat on specific week days only.
On the selected day between start date and end date they will occur on specific time.
- (id)initRecurrenceWithFrequency:(EKRecurrenceFrequency)type interval:(NSInteger)interval daysOfTheWeek:(NSArray *)days daysOfTheMonth:(NSArray *)monthDays monthsOfTheYear:(NSArray *)months weeksOfTheYear:(NSArray *)weeksOfTheYear daysOfTheYear:(NSArray *)daysOfTheYear setPositions:(NSArray *)setPositions end:(EKRecurrenceEnd *)end
appeared to be close but as far as i understand the doc i think i will have to use a combination of events.
I need pointers in direction of creating reminders which happen on specific times of day-> on specific day of week ->within specific start date and end date
Thank you
EDIT
I have tried following things and have faced some problem got some success
EKEvent *event = [EKEvent eventWithEventStore:kEVENTSTORE_SINGLTON];
event.title = #"Event Title test";
event.notes= #"Hope this one displays";
NSArray* rulesArray = [event recurrenceRules];
for (EKRecurrenceRule* rule in rulesArray) [event removeRecurrenceRule:rule];
event.startDate = [NSDate date]; //today
event.endDate = [event.startDate dateByAddingTimeInterval:60*60]; //set 1 hour meeting
[event setCalendar:[kEVENTSTORE_SINGLTON defaultCalendarForNewEvents]];
NSDate *date = [NSDate date];
EKAlarm *alarm1 = [EKAlarm alarmWithAbsoluteDate:[date dateByAddingTimeInterval:60]];
// [event addAlarm:alarm1];
EKAlarm *arm=[EKAlarm alarmWithRelativeOffset:60];
EKAlarm *alarm2 = [EKAlarm alarmWithAbsoluteDate:[date dateByAddingTimeInterval:120]];
// [event addAlarm:alarm2];
EKAlarm *alarm3 = [EKAlarm alarmWithAbsoluteDate:[date dateByAddingTimeInterval:180]];
// [event addAlarm:alarm3];
EKAlarm *alarm4 = [EKAlarm alarmWithAbsoluteDate:[date dateByAddingTimeInterval:240]];
//[event addAlarm:alarm4];
EKRecurrenceRule *objRecurrenceRule=[[EKRecurrenceRule alloc]initRecurrenceWithFrequency:EKRecurrenceFrequencyWeekly interval:1 daysOfTheWeek:#[[EKRecurrenceDayOfWeek dayOfWeek:EKFriday]] daysOfTheMonth:nil monthsOfTheYear:nil weeksOfTheYear:nil daysOfTheYear:nil setPositions:nil end:[EKRecurrenceEnd recurrenceEndWithOccurrenceCount:1]];
//[event addRecurrenceRule:objRecurrenceRule];
event.recurrenceRules=#[objRecurrenceRule];
event.alarms=#[arm];//if i add the relative alarm it works if i add absolute alarm it dosnt.
NSError *err = nil;
[kEVENTSTORE_SINGLTON saveEvent:event span:EKSpanFutureEvents commit:YES error:&err];
if(err)
NSLog(#"some error occured");
So i observed that recurrence rule works with relative alarm that makes sence becoz if alarm has to occour every Friday whats the point of giving absolute alarm
but my requirement is i want alarm to ring every friday say 5 PM date can be relative but time has to be fixed how can i achieve this?

Using EventStore, can I create a new iCal calendary type?

So in my app I rely heavily on iCal, and I can add events using EventStore, but only to the "defaultCalendarForNewEvents". I want to make a new calendar just for the events I create in the app, let's say MyApp calendar, which would behave much like the iCal calendars like "Home", "Work", etc.
Is there a way to do this programmatically?
Right now, I've tried this:
EKEventStore *eventStore = [[EKEventStore alloc] init];
NSArray *calendars = [eventStore calendars];
BOOL calendarHasBeenInitialized = NO;
for(NSCalendar *cal in calendars)
{
if([cal.calendarIdentifier isEqualToString:#"Workout Tracker"])
{
calendarHasBeenInitialized = YES;
}
}
if(!calendarHasBeenInitialized)
{
NSString *string = [[NSString alloc] initWithString:#"Workout Tracker"];
NSCalendar *workoutCalendar = (__bridge NSCalendar *)(CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault, (__bridge CFStringRef)string));
EKCalendar *ekcalendar = (EKCalendar *)workoutCalendar;
NSError *error;
[eventStore saveCalendar:ekcalendar commit:YES error:&error];
}
This is called in my App Delegate where if the calendar is not in the calendars array, I attempt to create it. This however, does not work.
Any help would be appreciated!
According to the docs, use EKCalendar's +calendarWithEventStore: method to create a new calendar in the event store you specify. I expect it'd go like this:
EKCalendar *newCalendar = [EKCalendar calendarWithEventStore:eventStore];

Resources