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'
Related
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!
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.
I'm on Xcode 6.0.1, making a test app with Event Kit. The following code successfully populates each event's title, but its notes are returned as (null) even when hasNotes property returns YES. And, I can see the notes for the same event on iPhone's default calendar app.
What am I doing wrong?
- (void)viewDidLoad
{
[super viewDidLoad];
[eventStore requestAccessToEntityType:EKEntityTypeEvent
completion:^(BOOL granted, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error)
{
NSLog(#" !! error");
// display error message here
}
else if (!granted)
{
NSLog(#"Not Granted");
// display access denied error message here
}
else
{
// access granted
NSCalendar *calendar = [NSCalendar currentCalendar];
// Create the start date components
NSDateComponents *oneWeekAgoComponents = [[NSDateComponents alloc] init];
oneWeekAgoComponents.day = -1;
NSDate *oneWeekAgo = [calendar dateByAddingComponents:oneWeekAgoComponents toDate:[NSDate date] options:0];
// Create the end date components
NSDateComponents *oneMonthFromNowComponents = [[NSDateComponents alloc] init];
oneMonthFromNowComponents.month = 1;
NSDate *oneMonthFromNow = [calendar dateByAddingComponents:oneMonthFromNowComponents toDate:[NSDate date] options:0];
// Create the predicate from the event store's instance method
NSPredicate *predicate = [eventStore predicateForEventsWithStartDate:oneWeekAgo endDate:oneMonthFromNow calendars:nil];
// Fetch all events that match the predicate
_eventArray = [eventStore eventsMatchingPredicate:predicate];
[self.tableView reloadData];
}
});
}];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
EKEvent *event = [self.eventArray objectAtIndex:indexPath.row];
cell.textLabel.text = event.title;
if (event.hasNotes) {
cell.detailTextLabel.text = event.notes;
} else {
cell.detailTextLabel.text = #"";
}
return cell;
}
I haven't fully resolved it, but got a clue.
NSArray *events = [eventStore eventsMatchingPredicate:predicate];
This didn't get the notes. So, instead I enumerate through returned events by doing
[eventStore enumerateEventsMatchingPredicate:predicate usingBlock:^(EKEvent *event, BOOL *stop) {
NSLog(#"title: %#",event.title);
NSLog(#"hasNotes: %s",event.hasNotes ? "YES":"NO");
NSLog(#"notes: %#",event.notes);
NSLog(#"-----");
[_eventTitles addObject:event.title];
[_eventTitles addObject:event.hasNotes ? event.notes : #""];
}];
This one returns actual notes (null).
I had a similar issue like this but when accessing the calendar object from the EKEvent. I my case this was because I had released the EKEventStore instance before I attempted to access the calendar (in cellForRowAtIndexPath:).
According to the Apple documentation "Reading and Writing Calendar Events":
An event store instance must not be released before other Event Kit
objects; otherwise, undefined behavior may occur.
https://developer.apple.com/library/mac/documentation/DataManagement/Conceptual/EventKitProgGuide/ReadingAndWritingEvents.html#//apple_ref/doc/uid/TP40004775-SW1
I want to synchronise all events with Google Calendar. I used the following code to do this: EKEventStore *eventStore = [[[EKEventStore alloc] init] autorelease];
calendarsArray = [[NSArray alloc] init];
calendarsArray = [[eventStore calendars] retain];
EKCalendar *calendar = [calendarsArray objectAtIndex:1];
[events setCalendar:calendar];
NSError *err;
[eventStore saveEvent:events span:EKSpanThisEvent error:&err];
But I am not getting google calendar at object at index(1). So Can anybody help me to solve this problem.
Please note that calendars is deprecated in iOS 6 use this instead:
(NSArray *)calendarsForEntityType:(EKEntityType)entityType
Entity type then needs to be one of these:
typedef enum {
EKEntityTypeEvent,
EKEntityTypeReminder
} EKEntityType;
This should give you the expected result, more info: https://developer.apple.com/library/ios/documentation/EventKit/Reference/EKEventStoreClassRef/Reference/Reference.html#//apple_ref/occ/instm/EKEventStore/calendarsForEntityType:
[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];