Предупреждение о получении памяти в ARC
Я звоню syncWithCalendar, и после успешного добавления событий я получаю предупреждение о нехватке памяти, и приложение завершает работу с предупреждением "Получено мало памяти". Событий, сгенерированных и сохраненных в календаре, более 50. Я пытался использовать инструменты, но я не смог найти код, где происходит утечка памяти, а также с помощью живых байтов, которые показывают на инструментах, я не могу отследить код, который вызывает протечь. Может кто-нибудь, пожалуйста, помогите мне решить эту проблему.
- (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
}
3 ответа
Вам нужно очистить кеш при получении предупреждения о памяти, используйте этот метод, он вам поможет.
-(void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
[[NSURLCache sharedURLCache] removeAllCachedResponses];
}
Это грубое предположение, но кажется, что асинхронные вызовы могут привести к проблемам.
Чтобы проверить это, просто используйте dispatch_sync
вместо dispatch_async
и изучить потребление памяти. Если это приведет к улучшению, тогда появится решение, которое заключается в том, чтобы повторно учесть ваш текущий асинхронный "параллельный" подход и превратить его в соответствующий асинхронный "последовательный" подход или полный синхронный подход.
Это также может потребовать "сериализации" всех вызовов этого асинхронного метода:
[eventStore requestAccessToEntityType:EKEntityTypeEvent
completion:^(BOOL granted, NSError *error) {
...
}]
Вот как я позвонил syncWithCalendar
функция
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
}
}];
}
И в syncWithCalendar
Функция все остается тем же, за исключением строки кода, которая была причиной сбоя / памяти. Ниже приведена неправильная строка кода, которую я использовал ранее
// wrong
[self.eventstore saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
Правильный способ сохранения события: (Примечание: в моем случае не требовался идентификатор события)
// correct
[self.eventstore saveEvent:event span:EKSpanThisEvent commit:NO error:&err];
а затем использовать [self.eventstore commit:NULL]
после того, как все события сохранены. Это остановило аварию в моем случае. Надеюсь, что этот пост поможет другим получить решение. Спасибо!!!!