Утечка памяти в NSMutableArray, NSArray, NSString в iPhone SDK - PullRequest
0 голосов
/ 16 апреля 2011

В моем приложении я получил утечки памяти в NSMutableArray, NSArray и NSString.

Вот код.

    NSString *subQuery = [NSString stringWithFormat:@"SELECT %@ FROM tbl_lang WHERE glossary = '%@'",append1,glossaryName];
    NSArray *subArray1 = [[[self returnExecuteQuery:subQuery] mutableCopy] autorelease];        
    [subArray addObjectsFromArray:subArray1];

    NSString *columnQuery = [NSString stringWithFormat:@"select AutoID,%@ from tbl_lang where glossary='%@'",lblshortName.text,glossaryName];
    NSArray *newArray =[[[self returnExecuteQuery:columnQuery] mutableCopy] autorelease];
    [langArray addObjectsFromArray:newArray];

    NSMutableArray *tempArray = [[NSMutableArray alloc] init];

    for (int i=0; i<[newArray count]; i++) {
        NSString *cellText = [[newArray objectAtIndex:i] valueForKey:[NSString stringWithFormat:@"%@",lblshortName.text]];

        if (cellText != (NSString *)[NSNull null] && ![cellText isEqualToString:@""] ) {
            NSString *decodedString3 = [NSString stringWithUTF8String:[cellText cStringUsingEncoding:[NSString defaultCStringEncoding]]];

            [tempArray addObject:[NSString stringWithFormat:@"%@ : %@",lblshortName.text, decodedString3]];
        }
        else {
            [tempArray addObject:@"<empty>"];
        }

        NSString *detail = @"_________________";

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

            NSString *checkNull=[[subArray1 objectAtIndex:i] valueForKey:[NSString stringWithFormat:@"%@",[lableNameArray objectAtIndex:j]]];

            if(checkNull != (NSString *)[NSNull null] && checkNull.length > 0)
            {
                NSString *decodedString4 = [NSString stringWithUTF8String:[checkNull cStringUsingEncoding:[NSString defaultCStringEncoding]]];
                detail = [NSString stringWithFormat:@"%@\n%@ : %@ ",detail,[lableNameArray objectAtIndex:j],decodedString4];
            }               
        }   
        [detailTextArray addObject:detail]; 

    }

Когда я запускаю в Instruments, я получаю утечки в

-subArray1 во второй строке.

-detail (NSString) во втором цикле for.

И subArray и langArray - мои глобальные массивы.

Если я удаляю mutableCopy из NSArray *newArray =[[[self returnExecuteQuery:columnQuery] mutableCopy] autorelease]; и NSArray *subArray1 = [[[self returnExecuteQuery:subQuery] mutableCopy] autorelease];, тогда subArray и langArray не сохраняют значения.

Как избежать утечки памяти в этом коде?

Ответы [ 3 ]

1 голос
/ 16 апреля 2011

Пожалуйста, попробуйте это, в приведенном выше коде вы создаете два объекта, которые принадлежат пулу авто-релиза. Вот одна из версий, в которой я пытался обработать освобождение этих строковых переменных.

Во-вторых, утечка detail связана с тем, что вы разыменовываете это много раз в вашем коде. А для subArray1 см. Комментарий

    NSMutableString *subQuery =[ [NSMutableString alloc] initWithFormat:@"SELECT %@ FROM tbl_lang WHERE glossary = '%@'",append1,glossaryName];
   // please make returnExecuteQuery's returned array autorelease if it is not.  
   NSArray *subArray1 = [[self returnExecuteQuery:subQuery] mutableCopy] ;
    [subArray addObjectsFromArray:subArray1];

    [subQuery release]; 
    NSMutableString *columnQuery ==[ [NSMutableString alloc] initWithFormat:@"select AutoID,%@ from tbl_lang where glossary='%@'",lblshortName.text,glossaryName];
    NSArray *newArray =[[self returnExecuteQuery:columnQuery] mutableCopy] ;
    [langArray addObjectsFromArray:newArray];
    [columnQuery relese];
    NSMutableArray *tempArray = [[NSMutableArray alloc] init];

    for (int i=0; i<[newArray count]; i++) {
        NSMutableString *tempKey = [[NSMutableString  alloc]initWithFormat:@"%@",lblshortName.text]];


        NSString *cellText = [[newArray objectAtIndex:i] valueForKey:tempKey];
        [tempKey release];

        if (cellText != (NSString *)[NSNull null] && ![cellText isEqualToString:@""] ) {
            NSString *decodedString3 = [NSString stringWithUTF8String:[cellText cStringUsingEncoding:[NSString defaultCStringEncoding]]];
            NSMutableString *tempString  = [[NSMutableString alloc] initWithFormat:@"%@ : %@",lblshortName.text, decodedString3]];

            [tempArray addObject:tempString];
            [tempString release];
        }
        else {
            [tempArray addObject:@"<empty>"];
        }

        NSMutableString *detail = nil;

        for (int j=0; j<[lableNameArray count]; j++) 
        {
             detail = [[ NSMutableString alloc]initWithString:@"_________________"];
            NSMutableString *key = [[NSMutableString alloc]initWithFormat:@"%@",[lableNameArray objectAtIndex:j]];
            NSString *checkNull=[[subArray1 objectAtIndex:i] valueForKey:key];
           [key release];

            if(checkNull != (NSString *)[NSNull null] && checkNull.length > 0)
            {
                NSString *decodedString4 = [NSString stringWithUTF8String:[checkNull cStringUsingEncoding:[NSString defaultCStringEncoding]]];
                [detail setString:[NSString stringWithFormat:@"%@\n%@ : %@ ",detail,[lableNameArray objectAtIndex:j],decodedString4]];
            } 
              [detailTextArray addObject:detail]; 
              [detail release];              
        }   


    }
    [subArray1 release];
    [newArray release];

UPDATE: Пожалуйста, прочитайте комментарии в коде и ответьте, чтобы все могло быть улучшено.

    NSMutableString *subQuery =[ [NSMutableString alloc] initWithFormat:@"SELECT %@ FROM tbl_lang WHERE glossary = '%@'",append1,glossaryName];
   //*****NOTE THIS POINT ----> please make returnExecuteQuery's returned array autorelease if it is not.  
   NSArray *subArray1 = [[self returnExecuteQuery:subQuery] mutableCopy] ;
    [subArray addObjectsFromArray:subArray1];

    [subQuery release]; 
    NSMutableString *columnQuery ==[ [NSMutableString alloc] initWithFormat:@"select AutoID,%@ from tbl_lang where glossary='%@'",lblshortName.text,glossaryName];
    //*****NOTE THIS POINT ----> please make returnExecuteQuery's returned array autorelease if it is not.  
    NSArray *newArray =[[self returnExecuteQuery:columnQuery] mutableCopy] ;
    [langArray addObjectsFromArray:newArray];
    [columnQuery relese];
    NSMutableArray *tempArray = [[NSMutableArray alloc] init];

    for (int i=0; i<[newArray count]; i++) {
        NSMutableString *tempKey = [[NSMutableString  alloc]initWithFormat:@"%@",lblshortName.text]];


        NSString *cellText = [[newArray objectAtIndex:i] valueForKey:tempKey];
        [tempKey release];

        if (cellText != (NSString *)[NSNull null] && ![cellText isEqualToString:@""] ) {
            NSString *decodedString3 = [NSString stringWithUTF8String:[cellText cStringUsingEncoding:[NSString defaultCStringEncoding]]];
            NSMutableString *tempString  = [[NSMutableString alloc] initWithFormat:@"%@ : %@",lblshortName.text, decodedString3]];

            [tempArray addObject:tempString];
            [tempString release];
        }
        else {
            [tempArray addObject:@"<empty>"];
        }

        NSMutableString *detail =  [[ NSMutableString alloc]initWithString:@"_________________"];

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

            NSMutableString *key = [[NSMutableString alloc]initWithFormat:@"%@",[lableNameArray objectAtIndex:j]];
            NSString *checkNull=[[subArray1 objectAtIndex:i] valueForKey:key]; //also here if you note you are using subArray1 not subArray?
           [key release];

            if(checkNull != (NSString *)[NSNull null] && checkNull.length > 0)
            {
                NSString *decodedString4 = [NSString stringWithUTF8String:[checkNull cStringUsingEncoding:[NSString defaultCStringEncoding]]];
                [detail setString:[NSString stringWithFormat:@"%@\n%@ : %@ ",detail,[lableNameArray objectAtIndex:j],decodedString4]];
               break;//I am not sure why you are checking this condition but assume that you want to get NOT NULL VALUE and  add it to array?
            } 

        }   
        [detailTextArray addObject:detail]; 
        [detail release];              

    }
    [subArray1 release];
    [newArray release];

ОБНОВЛЕНИЕ 2:

if(checkNull != (NSString *)[NSNull null] && checkNull.length > 0)
            {
                NSString *decodedString4 = [NSString stringWithUTF8String:[checkNull cStringUsingEncoding:[NSString defaultCStringEncoding]]];
                [detail appendFormat:@"%@\n%@ : %@ ",detail,[lableNameArray objectAtIndex:j],decodedString4]];

            }

Спасибо

1 голос
/ 16 апреля 2011

Не уверен, что вызывает утечку памяти, но это может помочь.Это более прямой способ копирования массивов, который может привести к предотвращению утечки:

NSArray *langArray =[[NSArray alloc] initWithArray: [self returnExecuteQuery:columnQuery] copyItems: YES];

В основном это одноуровневая глубокая копия массива, возвращаемого функцией returnExecuteQuery.Подробнее об этом можно прочитать в Темы программирования коллекций .

Я не уверен, как работает mutableCopy, и это может быть связано с утечкой.Если он копирует объекты в старом массиве, а затем добавляет их в новый массив, они могут войти в массив с счетом сохранения 2 (1 из копии и 1 из добавления в массив.)большой смысл, что это должно работать таким образом.Но, если это произойдет, это может объяснить утечку.

0 голосов
/ 16 апреля 2011

Вы можете начать с того, что выпустите свой tempArray, как только закончите с ним (после циклов).

Часто утечки более высоких уровней скрываются в потоке низкоуровневых (т.е. утечка контейнера вызывает все его содержимое).утечка), что может иметь место для вашей строки.

Кстати, использование mutableCopy] autorelease]; хорошо.

...