Предупреждение о получении памяти в 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] после того, как все события сохранены. Это остановило аварию в моем случае. Надеюсь, что этот пост поможет другим получить решение. Спасибо!!!!

Другие вопросы по тегам