Утечка памяти после второго просмотра tableview

#iphone #objective-c #core-data #memory-leaks

#iPhone #objective-c #core-данные #утечки памяти

Вопрос:

У меня есть два UITableViewControllers. Я нажимаю на второй и вызываю следующий метод в viewDidLoad.

Во второй раз, когда я удаляю это представление и возвращаюсь к первому представлению, я получаю утечку памяти.

Инструменты говорят, что проблема в последней строке следующего метода.

 - (void)fetchRecords {   

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:[NSEntityDescription entityForName:@"Articulation" inManagedObjectContext:[self managedObjectContext]]];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"articulationGroup == %@", selectedArticulationGroup];
    [request setPredicate:predicate];

    static NSArray *sortDescriptors = nil;
    if (!sortDescriptors)
        sortDescriptors = [[NSArray alloc] initWithObject:[[[NSSortDescriptor alloc] initWithKey:@"text" ascending:NO] autorelease]];
    [request setSortDescriptors:sortDescriptors];

    NSError *error = nil;
    NSArray *fetchResults = [managedObjectContext executeFetchRequest:request error:amp;error];
    if (!fetchResults)
        NSLog(@"no fetch results ArticulationsViewController, error %@", error);
    [request release];

    self.articulationsArray = [NSMutableArray arrayWithArray:fetchResults];

}
  

Понятия не имею … ложусь спать :'(

Ответ №1:

Во-первых, вы теряете свой массив sortDescriptors, если используете ветку распределения. <мыльница> Я настоятельно рекомендую вам использовать фигурные скобки вокруг всех блоков if / else, даже если в них всего одна строка — эти ошибки очень сложно обнаружить после факта</soapbox>

Пожалуйста, опубликуйте свой метод dealloc и объявления ivar.

Комментарии:

1. Я подумал то же самое, но sortDescriptors на самом деле статичен и, как ожидается, будет жить дальше.

2. Должен ли он выпускать статические sortDescriptors? Я бы подумал, что их нужно сохранить.

3. Вы оба правы; я не думаю, что sortDescriptors нужно выпускать. Что касается остального, нам нужно будет просмотреть другие соответствующие части кода, чтобы понять причину утечки.

Ответ №2:

Ну, я замечаю две вещи, которые могут быть правильными, но я все равно хотел спросить.

Прежде всего, вы спрашиваете в операторе if: if (!fetchResults) . Это означало бы, fetchResults что, возможно, не существует. Тем не менее, вы пытаетесь инициализировать массив с помощью этого.

Во-вторых, я не знаю, как вы распределили articulationsArray , но имеет ли изменение строки на self.articulationsArray = [[NSMutableArray alloc] initWithArray:fetchResults]] какой-либо эффект?

Комментарии:

1. self.articulationsArray = [[NSMutableArray alloc] initWithArray:fetchResults], скорее всего, создаст другую утечку, если articulationsArray является сохраненным свойством.

Ответ №3:

Почему ваш sortDescriptors массив статичен? Обычно вы бы сделали что-то вроде этого:

 NSSortDescriptor *textSort = [[NSSortDescriptor alloc] initWithKey:@"text" ascending:NO];

[fetchRequest setSortDescriptors:[NSArray arrayWithObject:textSort]];

[textSort release];
  

Кроме того, после if (!fetchResults) вам не следует сохранять свой массив, но сделайте что-то вроде этого:

 if (!fetchResults)
{
    NSLog(@"no fetch results ArticulationsViewController, error %@", error);
}
else
{
    NSMutableArray *articulationsArray_tmp = [fetchResults mutableCopy];
    self.articulationsArray = articulationsArray_tmp;
    [articulationsArray_tmp release];
}

[request release];
  

Также обратите внимание, как вы могли бы установить articulationsArray по-другому. Всегда следует быть осторожным с этими NSMutableArray s … 🙂

Ответ №4:

Этот блок совершенно не нужен и он опасен:

 static NSArray *sortDescriptors = nil;
if (!sortDescriptors)
    sortDescriptors = [[NSArray alloc] initWithObject:[[[NSSortDescriptor alloc] initWithKey:@"text" ascending:NO] autorelease]];
[request setSortDescriptors:sortDescriptors];
  

Любой статический объект опасен для памяти, и вы используете их только в особых случаях. Зачем привязывать массив только с локальной областью к определенному адресу / блоку? Все это можно заменить одной строкой:

 [request setSortDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortWithKey:@"text" ascending:NO]]];
  

… и это сделано.

Эта строка, вероятно, не нужна и, вероятно, вызовет проблемы позже:

 self.articulationsArray = [NSMutableArray arrayWithArray:fetchResults];
  

Зачем вам нужен изменяемый массив извлеченных объектов? На самом деле вы не можете добавлять или удалять что-либо из массива напрямую, сохраняя целостность вашего графика без повторной выборки.

Просто:

 self.articulationsArray = fetchResults;
  

в большинстве случаев будет работать нормально.

Чем больше объектов вы создаете, тем больше шансов на утечку вы создаете. Сделайте все как можно проще.

Комментарии:

1. Все хорошие моменты должным образом приняты к сведению. Это первый раз, когда я использую core data, и после этой утечки я начал копировать и вставлять материал отовсюду — я попробовал несколько разных методов, надеясь, что это исправит мою утечку.

Ответ №5:

Что ж… Я чувствую себя гусыней.

Когда я вернулся к своему первому TableViewController, я не выпускал articulationsArray.

Я использовал

 - (void)viewDidUnload {
    [self.articulationsArray release];
}
  

Когда я должен был использовать:

 -(void)viewDidDisappear:(BOOL)animated {
    [self.articulationsArray release];
}
  

viewDidUnload, никогда не вызывался.

Спасибо всем за вашу помощь.