Synchronization with google calendar - ios

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:

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!

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'

EKEvent.notes returns (null) even when EKEvent.hasNotes returns YES

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

Receiving An Intermittent EXC_BAD_ACCESS When Updating an EKEvent

I have a Cordova app with a custom plugin that is creating and updating EKEvents in the user's iCloud calendar.
I am using the following function to find a specific EKEvent based on its URL:
- (EKEvent*) getEventWithURL:(NSString *)pstrURL store:(EKEventStore *)pStore
{
EKCalendar* calendar = [self getCalendarByName:mstrCalendarName store:pStore createIfDoesNotExist:false];
NSArray* calendars = [[NSArray alloc] initWithObjects: calendar, nil];
NSDateFormatter *sDate = [[NSDateFormatter alloc] init];
[sDate setDateFormat:#"yyyy-MM-dd HH:mm"];
NSDate *myStartDate = [sDate dateFromString:#"2013-11-01 00:00"];
NSDateFormatter *eDate = [[NSDateFormatter alloc] init];
[eDate setDateFormat:#"yyyy-MM-dd HH:mm"];
NSDate *myEndDate = [eDate dateFromString:#"2014-12-31 23:59"];
NSPredicate *predicate = [pStore predicateForEventsWithStartDate:myStartDate endDate:myEndDate calendars: calendars];
// Fetch all events that match the predicate.
NSArray *events = [pStore eventsMatchingPredicate:predicate];
EKEvent *foundEvent = nil;
EKEvent *event;
for (id oEvent in events)
{
event = (EKEvent *)oEvent;
if ([event.URL isEqual:[NSURL URLWithString:pstrURL]])
{
foundEvent = event;
break;
}
}
return foundEvent;
}
It is then modified (start and end dates are changed) and saved in another method with the following code:
EKEvent *myEvent = nil;
BOOL saved = false;
EKCalendar* calendar = nil;
if(pstrCalendarTitle == nil)
{
calendar = pStore.defaultCalendarForNewEvents;
}
else
{
calendar = [self getCalendarByName: pstrCalendarTitle store: pStore createIfDoesNotExist:true];
}
// find event if it exists
myEvent = [self getEventWithURL:[NSString stringWithFormat: #"custom://%#", pstrTSDID ] store:pStore];
// if an event wasn't found, create a new one
if (myEvent == nil)
{
myEvent = [EKEvent eventWithEventStore: pStore];
}
// set all the fields to new values
myEvent.title = pstrTitle;
myEvent.location = pstrLocation;
myEvent.notes = pstrMessage;
myEvent.startDate = pdtStartDate;
myEvent.endDate = pdtEndDate;
myEvent.calendar = calendar;
myEvent.URL = [NSURL URLWithString:[NSString stringWithFormat: #"custom://%#", pstrTSDID ]];
// only add an alarm if one hasn't been created already
if ([[myEvent alarms] count] == 0)
{
EKAlarm *reminder = [EKAlarm alarmWithRelativeOffset:-2*60*60];
[myEvent addAlarm:reminder];
}
When creating a whole bunch of EKEvents (about 30 in a row) I don't get the EXC_BAD_ACCESS error, however when updating events I get the EXC_BAD_ACCESS error intermittently. Sometimes it is on the first update, and sometimes I am able to update 10 before seeing the error, which then crashes my app.
I suspect it may have something to do with the foundEvent variable not being retained, however my project is using ARC so it is my understanding that I don't need to do any memory management tasks. Unless ARC is getting confused with the way the event variable is being cast and then passed around in the loop in getEventWithURL?
For full disclosure, I do have Enable Zombie Objects enabled and the stack trace that I see doesn't reference any of my methods specifically, it starts at start_wqthread and then references some EKEventStore _databasechangedexternally internal methods.
For what it's worth I wasn't able to figure out what the issue was with modifying the events so I am instead deleting the event (if it exists) and creating a new one. My getEventWithURL method is now called deleteEventWithURL which does the removal of the event from the store. The app is no longer crashing after making this change.

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