Не могу понять, как исправить утечки памяти на iPhone - PullRequest
2 голосов
/ 06 декабря 2010

Я запустил инструмент Leaks и обнаружил огромную утечку в моем словаре mutableDeepCopy, но я не могу понять, что не так с кодом. Есть предложения?

@interface RootViewController : UIViewController{

  NSDictionary *immutableDictionary;
  NSMutableDictionary *mutableDictionary;
}

Вот строка кода, которая выделена в Инструментах

self.mutableDictionary = [self.immutableDictionary mutableDeepCopy];

Вот метод создания изменяемой копии словаря

@interface NSDictionary(MutableDeepCopy)
  -(NSMutableDictionary *)mutableDeepCopy;
@end

Вот реализация метода, я выделил код, который, по словам Ликс, протекает на 100%

- (NSMutableDictionary *) mutableDeepCopy {
    NSMutableDictionary *dictionaryToReturn = [NSMutableDictionary dictionaryWithCapacity:[self count]];
    NSArray *keys = [self allKeys];

    for(id key in keys) {
        id value = [self valueForKey:key];
        id copy = nil;
        if ([value respondsToSelector:@selector(mutableDeepCopy)]) {
            copy = [value mutableDeepCopy];
        } else if ([value respondsToSelector:@selector(mutableCopy)]) {
            copy = [value mutableCopy]; //This is the Leak
        }
        if (copy == nil) {
            copy = [value copy];
        }
        [dictionaryToReturn setValue:copy forKey:key];
    }
    return dictionaryToReturn;
}

Ответы [ 3 ]

3 голосов
/ 06 декабря 2010

Как объявлена ​​ваша собственность?Если is retain или copy, то это не утечка.

Ваша проблема в том, что имя mutableDeepCopy предполагает, что оно возвращает сохраненный объект, а не автоматически освобожденный объект, как это происходит на самом деле.

Редактировать: А в самом mutableDeepCopy вам нужно освободить переменную copy после добавления в словарь.

3 голосов
/ 06 декабря 2010

Вам необходимо проанализировать это в свете правил управления памятью Apple .

Начиная с этой строки:

self.mutableDictionary = [self.immutableDictionary mutableDeepCopy];

Я ожидаю, что mutableDeepCopy вернет объект, который у меня есть, поэтому в какой-то момент мне нужно освободить или автоматически освободить его. например, * +1008 *

NSMutableDeepCopy* temp = [self.immutableDictionary mutableDeepCopy];
self.mutableDictionary = temp;
[temp release];

или

self.mutableDictionary = [[self.immutableDictionary mutableDeepCopy] autorelease];

Так что теперь нам нужно взглянуть на mutableDeepCopy. Поскольку в названии есть «копия», ему необходимо вернуть «принадлежащий» объект, что на практике означает «забыть» освободить возвращенный объект. Вы уже не смогли этого сделать при создании возвращенного объекта в первой строке, так как dictionaryWithCapacity: дает вам объект, которым вы не владеете. Замените его на

NSMutableDictionary *dictionaryToReturn = [[NSMutableDictionary alloc] initWithCapacity:[self count]];

Теперь он у вас есть.

Важно, чтобы ваша mutableDeepCopy подчинялась правилам, поскольку это означает, что вы можете обрабатывать объекты, возвращенные из mutableDeepCopy, mutableCopy и копировать точно таким же образом. Во всех трех случаях вам принадлежит копия объекта, которую вы вставляете в массив. Поскольку вы владеете им, вы должны освободить его, или он протечет, как вы узнали. Итак, в конце цикла вам нужно

[copy release];

Это остановит утечку.

2 голосов
/ 06 декабря 2010

mutableCopy увеличивает счет сохранения объекта, как и setValue:forKey:. Это означает, что когда dictionaryToReturn освобождается, у объекта, которому был вызван mutableCopy, сохраняется счетчик единиц.

Попробуйте сделать это вместо:

copy = [[value mutableCopy] autorelease];
...