Утечка памяти при обработке объекта Foundation из NSJSONSerialization


Я изо всех сил пытаюсь исправить утечку памяти в вспомогательной функции, которую я сделал. Вспомогательная функция принимает результат

+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError * _Nullable *)error 

И преобразует все листовые элементы в NSStrings, если они являются NSN-номерами.

Вот метод:

-(NSArray *) stringisizeObjects:(NSArray *)inputArray{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSMutableArray *mutable = [[NSMutableArray alloc] initWithCapacity:[inputArray count]];

    for (int i = 0; i < [inputArray count]; i++) {
        NSArray *keys = [inputArray[i] allKeys];

        NSMutableDictionary *addDictionary = [[NSMutableDictionary alloc] initWithCapacity:[keys count]];

        for (int j = 0; j < [keys count]; j++) {

            id theObject = [[inputArray[i] objectForKey:keys[j]]autorelease];

            if ([theObject isKindOfClass:[NSNumber class]]) {

                [addDictionary setObject:[theObject stringValue] forKey:keys[j]];
                [theObject release];

            }else if ([theObject isKindOfClass:[NSString class]]){
                [addDictionary setObject:[inputArray[i] objectForKey:keys[j]] forKey:keys[j]];
            }

        }
        [mutable addObject:addDictionary];
    }
    NSArray *returnArray = [mutable copy];

    [mutable removeAllObjects];
    [mutable release];
    [pool drain];
    return returnArray;
}

Вот как я получаю входной массив.

id parsedThingy = [NSJSONSerialization JSONObjectWithData:resultJSONData options:1 error:&jsonDecodeError];

Прежде чем я смогу передать результат в свой метод stringisize, я должен убедиться, что у меня есть NSArray NSDictionaries с соответствующими ключами.

NSArray *resultArray = [self stringisizeObjects:parsedThingy];

Инструмент утечки памяти X-кода имеет указал мне на этот метод как на причину моей проблемы.

Приборы, показывающие утечки

Как вы можете видеть, я пробовал упаковывать вещи в пулы авторелиза, авторелиза и выпуска. Я просто не вижу никакого пути вперед.

Это не ARC проект, который работает 24/7.

Edit: я воспользовался советом Droppy и попытался переписать метод, используя mutableCopy. Утечка все еще там. На данный момент моя единственная работа вокруг может быть изменить источник JSON отправлять только строки. : (

-(NSArray *) stringisizeObjects2:(NSArray *)inputArray{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSMutableArray *mutableArray = [inputArray mutableCopy];

    for (int i = 0; i < [mutableArray count]; i++) {
        NSMutableDictionary *mutableDict = [mutableArray[i] mutableCopy];
        NSArray *keys = [mutableDict allKeys];

        for (int j = 0; j < [keys count]; j++) {
            if ([[mutableDict objectForKey:keys[j]] isKindOfClass:[NSNumber class]]) {
                NSString *stringValue = [[mutableDict objectForKey:keys[j]] stringValue];

                [mutableDict removeObjectForKey:keys[j]];
                [mutableDict setObject:stringValue  forKey:keys[j]];
            }
        }
        mutableArray[i] = [mutableDict copy];
        [mutableDict release];
    }

    NSArray *returnArray = [mutableArray copy];

    [mutableArray release];
    [pool drain];
    return returnArray;
}
1 2

1 ответ:

Задача:

  1. addDictionary вызывается alloc, но не вызывает release или autorelease
  2. returnArray = [изменяемая копия]; / / did increase retainCount +1, need autorelease here
  3. id theObject = [inputArray[i] objectForKey:keys[j]]; / / не нужен авторелиз или релиз для объекта, которым вы не владеете
  4. добавьте NSAutoreleasePool сверху и снизу здесь просто ничего не делайте

Решение:

-(NSArray *) stringisizeObjects:(NSArray *)inputArray{
    NSMutableArray *mutable = [[NSMutableArray alloc] initWithCapacity:[inputArray count]];

    for (int i = 0; i < [inputArray count]; i++) {
        NSArray *keys = [inputArray[i] allKeys];

        NSMutableDictionary *addDictionary = [[NSMutableDictionary alloc] initWithCapacity:[keys count]];

        for (int j = 0; j < [keys count]; j++) {

            id theObject = [inputArray[i] objectForKey:keys[j]]; // not need autorelease

            if ([theObject isKindOfClass:[NSNumber class]]) {

                [addDictionary setObject:[theObject stringValue] forKey:keys[j]];
                //[theObject release]; // not need release value here

            }else if ([theObject isKindOfClass:[NSString class]]){
                [addDictionary setObject:[inputArray[i] objectForKey:keys[j]] forKey:keys[j]];
            }

        }
        [mutable addObject:addDictionary];
        [addDictionary release]; // release after not use
    }
    NSArray *returnArray = [[[NSArray alloc] initWithArray:mutable] autorelease]; // auto release for return value

    [mutable removeAllObjects];
    [mutable release];
    return returnArray;
}