I am working on an app, that gets a student's school lessons online and saves it to the iPhone's calendar.
Every time the lessons get updated, I want to delete all events from the calendar of the week, and then put in the updated lessons for the whole week.
I got no problems in adding the events, but sometimes the events don't get removed?
dispatch_queue_t queue = dispatch_queue_create("com.xxxxr.xxxxxx.calendar", NULL);
dispatch_async(queue, ^{
EKEventStore *eventStore = [[EKEventStore alloc] init];
[eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (granted){
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
EKCalendar *calendarIdentifier;
if ([defaults objectForKey:#"Calendar"] == nil || ![eventStore calendarWithIdentifier:[defaults objectForKey:#"Calendar"]]){
// Create Calendar if Needed
EKSource *theSource = nil;
for (EKSource *source in eventStore.sources) {
if (source.sourceType == EKSourceTypeCalDAV && [source.title isEqualToString:#"iCloud"]) {
theSource = source;
NSLog(#"iCloud Store Source");
break;
} else {
for (EKSource *source in eventStore.sources) {
if (source.sourceType == EKSourceTypeLocal) {
theSource = source;
NSLog(#"iPhone Local Store Source");
break;
}
}
}
}
EKCalendar *cal;
cal = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:eventStore];
cal.title = #"xxxxxxx";
cal.source = theSource;
[eventStore saveCalendar:cal commit:YES error:nil];
NSString *calendar_id = cal.calendarIdentifier;
[defaults setObject:calendar_id forKey:#"Calendar"];
calendarIdentifier = cal;
} else {
calendarIdentifier = [eventStore calendarWithIdentifier:[defaults objectForKey:#"Calendar"]];
NSLog(#"Calendar Existed");
}
/* NOW TO WHERE THE PROBLEM LIES! */
/* FIRST DELETE ALL EVENTS OF THIS WEEK */
NSArray *arrayOfIdentitiesToDelete = [defaults objectForKey:#"eventIdentities"];
for(NSString *identifierOfEventToDelete in arrayOfIdentitiesToDelete){
EKEvent *eventToRemove = [eventStore eventWithIdentifier:identifierOfEventToDelete];
NSError *error;
[eventStore removeEvent:eventToRemove span:EKSpanThisEvent error:&error];
}
/* Then create new events from my 'arrayOfLessons' array */
NSMutableArray *arrayOfEventIdentities = [[NSMutableArray alloc] init];
for(int dayAddingToCalendar = 0; dayAddingToCalendar < 5; dayAddingToCalendar++){
for(NSArray *arrayOfDayAddingToCalendar in [[arrayOfLessons objectAtIndex:dayAddingToCalendar] objectAtIndex:3]){
EKEvent *event = [EKEvent eventWithEventStore:eventStore];
event.calendar = calendarIdentifier;
event.title = [arrayOfDayAddingToCalendar objectAtIndex:4];
event.location = [arrayOfDayAddingToCalendar objectAtIndex:1];
event.notes = [arrayOfDayAddingToCalendar objectAtIndex:0];
event.startDate = [arrayOfDayAddingToCalendar objectAtIndex:12];
event.endDate = [arrayOfDayAddingToCalendar objectAtIndex:13];
event.allDay = NO;
[eventStore saveEvent:event span:EKSpanThisEvent error:nil];
[arrayOfEventIdentities addObject:event.eventIdentifier];
}
}
[defaults setObject:arrayOfEventIdentities forKey:#"eventIdentities"];
} else {
NSLog(#"Not Granted");
}
}];
});
You are saying:
NSError *error;
[eventStore removeEvent:eventToRemove span:EKSpanThisEvent error:&error];
So you are throwing away error-checking. Don't. Look at the error! That's what it's for. Like this:
NSError *error;
BOOL ok = [eventStore removeEvent:eventToRemove span:EKSpanThisEvent error:&error];
if (!ok)
NSLog(#"%#", error);
Related
In my application i am adding an event to devices calendar.I am doing like this
if ([db.saveCalenderSettings isEqualToNumber:[NSNumber numberWithBool:YES]]){
NSPredicate *predicateForEventOnDate = [store predicateForEventsWithStartDate:strtdate endDate:[strtdate dateByAddingTimeInterval:60*60] calendars:nil];
NSArray *eventsOnDate = [store eventsMatchingPredicate:predicateForEventOnDate];
__block BOOL eventExists = NO;
[eventsOnDate enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
EKEvent *eventToCheck = (EKEvent*)obj;
if([note isEqualToString:eventToCheck.notes]) {
eventExists = YES;
*stop = YES;
}
}];
NSLog(#"%#",eventsOnDate);
if(! eventExists) {
NSLog(#"Event not exists so adding");
EKEvent *event = [EKEvent eventWithEventStore:store];
event.title = subject; //give event title you want
event.notes = note ;
event.startDate = strtdate;
event.endDate = [event.startDate dateByAddingTimeInterval:60*60];
event.calendar = [store defaultCalendarForNewEvents];
// EKAlarm *alarm = [EKAlarm alarmWithRelativeOffset:60*15*-1];
// event.alarms = [NSArray arrayWithObject:alarm];
NSError *err = nil;
[store saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
if (!err) {
[db setSavedtocalender:#"yes"];
}
else {
// NSLog(#" Event not created");
[db setSavedtocalender:#"no"];
}
}
else {
NSLog(#"Event exists");
[db setSavedtocalender:#"yes"];
}
}
But the problem is the same event gets added multiple times in the default calendar .Can anybody tells me where i am going wrong?
Hi For each and every event one id is alloted.
Please Check is the event is added or not.If event added then store event id and check agin before saving event again.
For getting Event Id :
//save the event id if you want to access this later
NSString *eventId=event.eventIdentifier;
For Future Refernce :
// To add event in Calender App
EKEventStore *store = [EKEventStore new];
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (!granted) { return; }
EKEvent *event = [EKEvent eventWithEventStore:store];
event.title = #"To meet Chandu.";
event.startDate = [NSDate date]; //today
event.endDate = [event.startDate dateByAddingTimeInterval:60*60]; //set 1 hour meeting
event.calendar = [store defaultCalendarForNewEvents];
event.location=#"Sandriver Technologies";
NSError *err = nil;
[store saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
NSLog(#"%#",event.eventIdentifier); //save the event id if you want to access this later
eventId=event.eventIdentifier;
}];
//to remove event from app
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (!granted) { return; }
EKEvent* eventToRemove = [store eventWithIdentifier:eventId];
if (eventToRemove) {
NSError* error = nil;
[store removeEvent:eventToRemove span:EKSpanThisEvent commit:YES error:&error];
}
}];
// Note: Get all event list
//To get Appropriate calender
NSCalendar *calendar = [NSCalendar currentCalendar];
if ([store respondsToSelector:#selector(requestAccessToEntityType:completion:)])
{
/* iOS Settings > Privacy > Calendars > MY APP > ENABLE | DISABLE */
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error)
{
if ( granted )
{
NSLog(#"User has granted permission!");
// Create the start date components
NSDateComponents *oneDayAgoComponents = [[NSDateComponents alloc] init];
oneDayAgoComponents.day = -1;
NSDate *oneDayAgo = [calendar dateByAddingComponents:oneDayAgoComponents
toDate:[NSDate date]
options:0];
// Create the end date components
NSDateComponents *oneYearFromNowComponents = [[NSDateComponents alloc] init];
oneYearFromNowComponents.year = 1;
NSDate *oneYearFromNow = [calendar dateByAddingComponents:oneYearFromNowComponents
toDate:[NSDate date]
options:0];
// Create the predicate from the event store's instance method
NSPredicate *predicate = [store predicateForEventsWithStartDate:oneDayAgo
endDate:oneYearFromNow
calendars:nil];
// Fetch all events that match the predicate
NSArray *events = [store eventsMatchingPredicate:predicate];
NSLog(#"The content of array is%#",events);
}
else
{
NSLog(#"User has not granted permission!");
}
}];
}
I am new to programming I have made a Reminder App which saves the events on iCal and now i want to delete that events through the coding in the project, my code for creating events in iCal is below-
-(void) setReminderInPhone {
NSString *dateWithTime = [NSString stringWithFormat:#"%# %#",calenderDtl.dateInString,calenderDtl.openTimeUTC];
NSString *mrktName = mrktDtl.marketName;
//dateWithTime = #"2016-04-02 04:10 am";
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
fmt.dateFormat = #"yyyy-MM-dd hh:mm a";
[fmt setAMSymbol:#"am"];
[fmt setPMSymbol:#"pm"];
fmt.timeZone = [NSTimeZone timeZoneWithName:#"UTC"];
NSDate *utc = [fmt dateFromString:dateWithTime];
fmt.dateFormat = #"yyyy-MM-dd hh:mm a";
fmt.timeZone = [NSTimeZone systemTimeZone];
NSString *local = [fmt stringFromDate:utc];
NSDate *localDate = [fmt dateFromString:local];
EKEventStore *store = [EKEventStore new];
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (!granted) { return; }
EKEvent *event = [EKEvent eventWithEventStore:store];
event.title = mrktName;
event.startDate = localDate; //test
event.endDate = [event.startDate dateByAddingTimeInterval:60*2];
event.calendar = [store defaultCalendarForNewEvents];
NSError *err = nil;
[store saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
}];
}
Try following to remove event from Calendar.
EKEvent *eventToRemove = [eventStore eventWithIdentifier:eventIdentifier];
if (eventToRemove)
{
NSError* error = nil;
[eventStore removeEvent:eventToRemove span:EKSpanThisEvent commit:YES error:&error];
}
You will get the Value of eventIdentifier at the time of creating event in iCalendar as following :
//Adding Events to default iOS calendar for Making Reminders
-(NSString *)addEventToCalendar: (NSString *)title withDate:(NSString *)date{
EKEvent *event = [EKEvent eventWithEventStore:eventStore];
event.title = [NSString stringWithFormat:#"Pregnancy Workout Advisor - Event: %#",title];
event.startDate = [dateFormatter dateFromString:date];
event.endDate = [event.startDate dateByAddingTimeInterval:60*60]; //set 1 hour meeting
event.allDay = YES;
[dateFormatter setDateFormat:#"YYYY-MM-dd"];
EKAlarm *alarm = [EKAlarm alarmWithAbsoluteDate:[NSDate dateWithTimeInterval:9*60*60 sinceDate:[dateFormatter dateFromString:date]]];
[event addAlarm:alarm];
event.calendar = [eventStore defaultCalendarForNewEvents];
NSError *err = nil;
[eventStore saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
return event.eventIdentifier; }
In this above method, you will get a eventIdentifier for each event which you're adding to calendar. Store the eventIdentifier to CoreData/Sqlite, whatever..
So that, when you need to delete that event, just give that eventIdentifier. This will surely delete from Calendar.
Hope it helps...
try this code, its working for me,
EKEventStore *store = [[EKEventStore alloc] init];
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (!granted) return;
EKEvent* eventToRemove = [store eventWithIdentifier:[eventIdendifier objectAtIndex:indexPath.row]];
if (eventToRemove) {
[eventToRemove setCalendar:[store defaultCalendarForNewEvents]];
NSError* err = nil;
[store removeEvent:eventToRemove span:EKSpanThisEvent commit:YES error:&err];
dispatch_async(dispatch_get_main_queue(), ^{
[eventIdendifier removeObjectAtIndex:indexPath.row];
});
}
}];
i have give eventIdentifier value, its NSMutableArray value. first you add the event in Event Store you had each event got each event identifier value, its automatically save to eventIdentifier and get the identifier value method is below,
EKEventStore *store = [EKEventStore new];
if ([store respondsToSelector:#selector(requestAccessToEntityType:completion:)])
{
/* iOS Settings > Privacy > Calendars > MY APP > ENABLE | DISABLE */
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error)
{
if ( granted )
{
NSPredicate *predicate = [store predicateForEventsWithStartDate:date1 endDate:[date1 dateByAddingTimeInterval:23.96 * 60.0 * 60.0] calendars:nil];
NSMutableArray *eventsVal = (NSMutableArray *)[store eventsMatchingPredicate:predicate];
for (int i = 0; i<eventsVal.count; i++) {
[eventIdendifier addObject:[[eventsVal objectAtIndex:i] eventIdentifier]];
}
}
}];
}
its predicate the start date to end date check then got all events particular date and also add object from eventIdentifier value if the value help to show event Values, remove events etc
hope its helpful
I am using BOOL method to save event in my custom Calendar and strForCalanderID have calendarIdentifier value but that event is not save in particular calendar. It's working fine when I am adding event on default calendar but not in custom or user created calendar.
-(BOOL)addEventOnICal:(NSMutableDictionary*)eventDict{
EKCalendar *calendar = nil;
NSString *calendarIdentifier =strForCalanderID;//strForCalanderID=> custom Calendar identifier
if (calendarIdentifier) {
calendar = [eventStore calendarWithIdentifier:calendarIdentifier];
calendar.title=strForCalanderName;
}
if (!calendar) {
// http://stackoverflow.com/questions/7945537/add-a-new-calendar-to-an-ekeventstore-with-eventkit
calendar = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:eventStore];
for (EKSource *s in eventStore.sources) {
if (s.sourceType == EKSourceTypeLocal) {
calendar.source = s;
break;
}
}
NSString *calendarIdentifier = [calendar calendarIdentifier];
NSError *error = nil;
BOOL saved = [eventStore saveCalendar:calendar commit:YES error:&error];
if (saved) {
} else {
// unable to save calendar
return NO;
}
}
// this shouldn't happen
if (!calendar) {
return NO;
}
[event setCalendar:[eventStore defaultCalendarForNewEvents]];
event.location = #"Indore";
event.title = #"Hello Test";
// set the start date to the current date/time and the event duration to two hours
event.startDate = StartDate;
event.endDate = EndDate;
NSError *error = nil;
// save event to the callendar
BOOL result = [eventStore saveEvent:event span:EKSpanThisEvent commit:YES error:&error];
if (result) {
return YES;
} else {
// NSLog(#"Error saving event: %#", error);
// unable to save event to the calendar
return NO;
}
}
I am making a call to syncWithCalendar and after events are successfully added, I get low memory warning and app terminates with "Received Low Memory" warning. The events generated and saved in calendar are more than 50. I tried using instruments but I am not able to find the code where memory leak occurs and also through live bytes that show in instruments I am not able to track the code that is causing the leak. Can anyone please help me solve this issue.
- (void)syncWithCalendar
{
#autoreleasepool {
[self deleteEventsIfExist];
NSMutableDictionary *dictionary = [util readPListData];
NSMutableArray *courses = [util getCourses];
__block NSMutableArray *lessons;
__block NSMutableDictionary *lesson;
NSString *studentID = [util getProgramDetails].studentId;
NSString *programName = [util getProgramDetails].programName;
double offset[] = {0, 0, -300, -900, -1800, -3600, -7200, -86400, -172800};
__block NSString *startDateString = #"", *endDateString = #"";
NSTimeInterval relativeOffsetValue = 0;
int index = [[dictionary objectForKey:#"event-alert-option"] intValue];
relativeOffsetValue = offset[index];
NSDateFormatter *formatter;
formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MM/dd/yyyy HH:mm:ss"];
[formatter setDateFormat:#"MM/dd/yyyy"];
NSString *currentDateString = [NSString stringWithFormat:#"%# 09:00:00", [formatter stringFromDate:[NSDate date]]];
[formatter setDateFormat:#"MM/dd/yyyy HH:mm:ss"];
NSDate *currentDate = [formatter dateFromString:currentDateString];
EKEventStore *eventStore = [[EKEventStore alloc] init];
if([eventStore respondsToSelector:#selector(requestAccessToEntityType:completion:)]) {
// iOS 6 and later
[eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (granted){
//---- codes here when user allow your app to access theirs' calendar.
dispatch_async(dispatch_get_main_queue(), ^{
// Event creation code here.
for (int i=0; i<[courses count]; i++)
{
#autoreleasepool {
lessons = [[courses objectAtIndex:i] objectForKey:#"lessons"];
for (int j=0; j<[lessons count]; j++)
{
#autoreleasepool {
lesson = [lessons objectAtIndex:j];
NSString *title = nil;
title = [NSString stringWithFormat:#"%# %#-Complete %# lesson",studentID,programName,[lesson objectForKey:#"lesson-name"]];
if ([[lesson objectForKey:#"actual-exam-date"] isEqualToString:#"00/00/0000"])
{
startDateString = [NSString stringWithFormat:#"%# %#", [lesson objectForKey:#"plan-exam-date"], #"09:00:00"];
endDateString = [NSString stringWithFormat:#"%# %#", [lesson objectForKey:#"plan-exam-date"], #"18:00:00"];
}
else
{
if ([[lesson objectForKey:#"retake-actual-date"] isEqualToString:#"00/00/0000"])
{
startDateString = [NSString stringWithFormat:#"%# %#", [lesson objectForKey:#"retake-plan-date"], #"09:00:00"];
endDateString = [NSString stringWithFormat:#"%# %#", [lesson objectForKey:#"retake-plan-date"], #"18:00:00"];
}
}
if (!([startDateString isEqualToString:#""] && [endDateString isEqualToString:#""]))
{
EKEvent *event = [EKEvent eventWithEventStore:eventStore];
event.title=title;
event.startDate = [formatter dateFromString:startDateString];
event.endDate = [formatter dateFromString:endDateString];
event.allDay = NO;
if (index != 0)
{
event.alarms = [NSArray arrayWithObjects:[EKAlarm alarmWithRelativeOffset:relativeOffsetValue], nil];
}
[event setCalendar:[eventStore defaultCalendarForNewEvents]];
// Compare current date to event start date, if start date has been passed then preventing to sync with calendar
NSComparisonResult result = [event.startDate compare:currentDate];
if (result != NSOrderedAscending)
{
NSError *err = nil;
[eventStore saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
if (err) {
NSLog(#"event not saved .. error = %#",err);
} else {
NSLog(#"event added successfully");
}
}
}
} // autoreleasepool
} // lessons for loop
} // autoreleasepool
} // courses for loop
[self hideModal];
});
}else
{
//----- codes here when user NOT allow your app to access the calendar.
// [self performSelectorOnMainThread:#selector(hideModal) withObject:nil waitUntilDone:NO];
}
}];
} else {
// sync calendar for <iOS6
}
} // autoreleasepool
}
- (void)deleteEventsIfExist
{
#autoreleasepool {
NSMutableArray *courses = [util getCourses];
__block NSMutableArray *lessons;
__block NSMutableDictionary *lesson;
NSString *studentID = [util getProgramDetails].studentId;
NSString *programName = [util getProgramDetails].programName;
EKEventStore* store = [[EKEventStore alloc] init];
dispatch_async(dispatch_get_main_queue(), ^{
// Event creation code here.
NSDate* endDate = [NSDate dateWithTimeIntervalSinceNow:[[NSDate distantFuture] timeIntervalSinceReferenceDate]];
NSPredicate *fetchCalendarEvents = [store predicateForEventsWithStartDate:[NSDate date] endDate:endDate calendars:store.calendars];
NSArray *allEvents = [store eventsMatchingPredicate:fetchCalendarEvents];
for (int i=0; i<[courses count]; i++)
{
#autoreleasepool {
lessons = [[courses objectAtIndex:i] objectForKey:#"lessons"];
for (int j=0; j<[lessons count]; j++)
{
#autoreleasepool {
lesson = [lessons objectAtIndex:j];
NSString *oldEventSubtitle = [NSString stringWithFormat:#"%# %#-Complete %# lesson",studentID,programName,[lesson objectForKey:#"lesson-name"]];
for (EKEvent *e in allEvents)
{
if ( [oldEventSubtitle isEqualToString:e.title])
{
NSError* error = nil;
[store removeEvent:e span:EKSpanThisEvent commit:YES error:&error];
NSLog(#"deleting events");
}
}
} // autoreleasepool
} // lessons
} // autoreleasepool
} // courses
});
} // autoreleasepool
}
It's a rough guess, but it seems the asynchronous invocations may lead to troubles.
In order to test this, just use dispatch_sync instead of dispatch_async and examine the memory consumption. If this leads to an improvement, then a solution is in sight, which involves to re-factor your current asynchronous "parallel" approach and turn it into an appropriate asynchronous "serial" approach or an complete synchronous approach.
This may also require to "serialize" all invocations of this asynchronous method:
[eventStore requestAccessToEntityType:EKEntityTypeEvent
completion:^(BOOL granted, NSError *error) {
...
}]
This is how I made a call to syncWithCalendar function
if([eventStore respondsToSelector:#selector(requestAccessToEntityType:completion:)]) {
// iOS 6 and later
[eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted,
NSError *error) {
if (granted){
dispatch_async(dispatch_get_main_queue(), ^{
[self syncWithCalendar];
});
} else {
// calendar access not granted
}
}];
}
And in syncWithCalendar function everything remains same except the line of code that
was creating the crash/memory issue. Below is the incorrect line of code that I was
using earlier
// wrong
[self.eventstore saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
The correct way to save event: (Note: I didn't require event identifier in my case)
// correct
[self.eventstore saveEvent:event span:EKSpanThisEvent commit:NO error:&err];
and then use [self.eventstore commit:NULL] after all the events are saved. This stopped the crash in my case. Hope this post will
help other get the solution. Thanks !!!!
You need to clear the cache when you are receiving memory warning, use this method it will help you.
-(void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
[[NSURLCache sharedURLCache] removeAllCachedResponses];
}
- (void)syncWithCalendar
{
NSMutableDictionary *dictionary = [util readPListData];
NSMutableArray *courses = [util getCourses];
__block NSMutableArray *lessons;
__block NSMutableDictionary *lesson;
NSString *studentID = [util getProgramDetails].studentId;
NSString *programName = [util getProgramDetails].programName;
__block NSString *startDateString = #"", *endDateString = #"";
NSDateFormatter *formatter;
formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MM/dd/yyyy HH:mm:ss"];
[formatter setDateFormat:#"MM/dd/yyyy"];
NSString *currentDateString = [NSString stringWithFormat:#"%# 09:00:00", [formatter stringFromDate:[NSDate date]]];
[formatter setDateFormat:#"MM/dd/yyyy HH:mm:ss"];
NSDate *currentDate = [formatter dateFromString:currentDateString];
self.eventstore = [[EKEventStore alloc] init];
[self.eventstore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error)
{
if (granted) {
NSLog(#"calendar access granted");
for (int i=0; i<[courses count]; i++)
{
lessons = [[courses objectAtIndex:i] objectForKey:#"lessons"];
for (int j=0; j<[lessons count]; j++)
{
lesson = [lessons objectAtIndex:j];
NSString *title = nil;
title = [NSString stringWithFormat:#"%# %#-Complete %# lesson",studentID,programName,[lesson objectForKey:#"lesson-name"]];
startDateString = [NSString stringWithFormat:#"%# %#", [lesson objectForKey:#"exam-date"], #"09:00:00"];
endDateString = [NSString stringWithFormat:#"%# %#", [lesson objectForKey:#"exam-date"], #"18:00:00"];
if (!([startDateString isEqualToString:#""] && [endDateString isEqualToString:#""]))
{
EKEvent *event = [EKEvent eventWithEventStore:self.eventstore];
event.title=title;
event.startDate = [formatter dateFromString:startDateString];
event.endDate = [formatter dateFromString:endDateString];
event.allDay = NO;
[event setCalendar:[self.eventstore defaultCalendarForNewEvents]];
NSError *err = nil;
[self.eventstore saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
//[self.eventstore saveEvent:event span:EKSpanThisEvent error:&err];
if (err) {
NSLog(#"event not saved .. error = %#",err);
} else {
NSLog(#"event added successfully");
}
}
} // lessons for loop
} // courses for loop
} else {
NSLog(#"Access not granted");
}
}];
[self.eventstore release];
[formatter release];
}
After events gets successfully added it shows:
"Received Memory Warning. Terminating in response to SpringBoard's termination"
and the app terminates. This is happening in iOS 7 device. I haven't checked it yet in iOS 6 and below. The code works fine if there are only a few events saved (30 or less) but it shows memory issue for 80 events or more on saving.
Finally I found the answer to my question. I would like to share my solution so that it can help others ....
I was specially getting the crash in iOS 7 and it was because of the below line
// wrong
[self.eventstore saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
The correct way to save event: (Note: I didn't require event identifier for my case)
// correct
[self.eventstore saveEvent:event span:EKSpanThisEvent commit:NO error:&err];
and then use
[self.eventstore commit:NULL]
after all the events are saved.
This stopped the crash in my case.
Switching to ARC may solve the problem with memory but problems may still occur with large amount of data.
Try using #autorelease pools inside for loop as in example
for (int i=0; i<[courses count]; i++)
{
#autoreleasepool {
lessons = [[courses objectAtIndex:i] objectForKey:#"lessons"];
for (int j=0; j<[lessons count]; j++)
{
lesson = [lessons objectAtIndex:j];
NSString *title = nil;
title = [NSString stringWithFormat:#"%# %#-Complete %# lesson",studentID,programName,[lesson objectForKey:#"lesson-name"]];
startDateString = [NSString stringWithFormat:#"%# %#", [lesson objectForKey:#"exam-date"], #"09:00:00"];
endDateString = [NSString stringWithFormat:#"%# %#", [lesson objectForKey:#"exam-date"], #"18:00:00"];
if (!([startDateString isEqualToString:#""] && [endDateString isEqualToString:#""]))
{
EKEvent *event = [EKEvent eventWithEventStore:self.eventstore];
event.title=title;
event.startDate = [formatter dateFromString:startDateString];
event.endDate = [formatter dateFromString:endDateString];
event.allDay = NO;
[event setCalendar:[self.eventstore defaultCalendarForNewEvents]];
NSError *err = nil;
[self.eventstore saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
//[self.eventstore saveEvent:event span:EKSpanThisEvent error:&err];
if (err) {
NSLog(#"event not saved .. error = %#",err);
} else {
NSLog(#"event added successfully");
}
}
} // lessons for loop
}//autoreleasepool
} // courses for loop
This way each for loop step will release all autorelease objects.
#upendar I also have same scenario but i am split into small chunks, I.E. Like if you have 80 events to sync take 20-20 and pause 2-5sec. between them.
autoreleasepool is good to use, But it Calendar took too much memory to execute. It will take more then 100% some time.
I bared with this issue. Really interesting one!!!