Receiving memory warning after saving 80 ekevents

630 Views Asked by At
- (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.

3

There are 3 best solutions below

4
On

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.

1
On

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.

0
On

@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!!!