Утечка памяти на iPhone :( - PullRequest
1 голос
/ 08 июня 2009

Я новичок в C, Obj-C и iPhone, и я пытаюсь справиться с большим количеством используемой терминологии. Я надеюсь, что один из вас сможет помочь с проблемой, с которой я боролся уже несколько дней.

Мой код ниже - это метод, который вызывает перо, содержащее поле поиска и таблицу. Таблица заполняется поиском массива, созданного для «theList» ниже. Используя «Инструменты», я получаю утечку в строке: NSDictionary * theItem = [NSDictionary dictionaryWithObjectsAndKeys: clientName, @ "Name", clientId, @ "Id", nil]; , но я не могу понять, почему: (

Я знаю, что это, вероятно, трудный вопрос, но если кто-нибудь может помочь!

- (void)editClient:(id)sender {

    if (pickList == nil) {
        pickList = [[PickFromListViewController alloc] initWithNibName:@"PickList" bundle:nil];
    }

    TimeLogAppDelegate *appDelegate = (TimeLogAppDelegate *)[[UIApplication sharedApplication] delegate];
    NSMutableArray *theList = [[NSMutableArray alloc] init];
    int i;
    for (i=0;i < [appDelegate.clients count];i++) {
        Client *thisClient = [appDelegate.clients objectAtIndex:i];
        NSString *clientName = [[NSString alloc] initWithString: thisClient.clientsName];
        NSNumber *clientId = [[NSNumber alloc] init];
        clientId = [NSNumber numberWithInt:thisClient.clientsId];
        NSDictionary *theItem = [NSDictionary dictionaryWithObjectsAndKeys:clientName,@"Name",clientId,@"Id",nil];
        [theList addObject:theItem];
        theItem = nil;
        [clientName release];
        [clientId release];
    }
    [pickList createSearchItems:theList :NSLocalizedString(@"Client",nil)];
    [theList release];

    appDelegate.returningID = [NSNumber numberWithInt: projectsClientsId];
    [self.navigationController pushViewController:pickList animated:YES];

}

Заранее спасибо!

Ответы [ 3 ]

9 голосов
/ 08 июня 2009

Возвращает выделенный экземпляр NSNumber.

NSNumber *clientId = [[NSNumber alloc] init];

Эта строка перезаписывает вышеуказанный clientId другим экземпляром NSNumber, numberWithInt возвращает объект автоматического освобождения, так как для него не выделена память, вызывать его не следует, он будет освобожден автоматически.

clientId = [NSNumber numberWithInt:thisClient.clientsId];

Вы вызываете release для clientId, поэтому у вас проблема с памятью. Чтобы исправить это, удалите первую строку выше, которая в данном случае бесполезна, и обновите вторую строку:

NSNumber * clientId = [NSNumber numberWithInt:thisClient.clientsId];

Затем удалите:

[clientId release]

Поскольку clientId будет освобожден автоматически.

РЕДАКТИРОВАТЬ : Re все еще есть проблемы ... Я не уверен, как вам манипулировать клиентами в делегате приложения, иначе код должен работать нормально, я создал небольшой пример, пропуская части, которые я не вижу (делегат приложения и клиенты):

// утилита командной строки - проект инструмента фундамента:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

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

    int i = 0;
    for (i = 0; i < 10; ++i)
    {
        NSString * clientName = [NSString stringWithString:@"client"];  //no need to release
        NSNumber * clientId = [NSNumber numberWithInt:i];
        NSDictionary * theItem = [NSDictionary dictionaryWithObjectsAndKeys:
                                  clientName, @"name",
                                  clientId, @"id",
                                  nil];

        [theList addObject:theItem];
    }

    for (id item in theList) for (id key in item) NSLog(@"%@ - %@", key, [item objectForKey:key]);

    [theList release];
    [pool drain];
    return 0;
}
3 голосов
/ 08 июня 2009

Вы создаете clientID с [[NSNumber alloc] init], а затем немедленно перезаписываете его с помощью автоматически выпущенного экземпляра NSNumber [NSNumber numberWithInt], а затем вы выпускаете его позже в своем коде, чего не следует делать. Избавьтесь от линии [[NSNumber alloc] init] и [clientId release], и это должно исправить это.

1 голос
/ 15 июня 2009

Помимо очевидной утечки NSNumber, есть несколько других вещей, которые я мог бы исправить, которые могут помочь. Большинство из них довольно незначительные, но по моему опыту с Objective-C, меньше кода == более ясный код, что не в равной степени относится к таким языкам, как Bash или Perl. ; -)

- (void) editClient:(id)sender {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  if (pickList == nil) {
    pickList = [[PickFromListViewController alloc] initWithNibName:@"PickList" bundle:nil];
  }
  TimeLogAppDelegate *appDelegate = (TimeLogAppDelegate*)[[UIApplication sharedApplication] delegate];

  NSMutableArray *searchItems = [NSMutableArray array];
  NSMutableDictionary *itemDict = [NSMutableDictionary dictionary];
  for (Client *client in appDelegate.clients) {
    [itemDict setObject:[client.clientsName copy]                 forKey:@"Name"];
    [itemDict setObject:[NSNumber numberWithInt:client.clientsId] forKey:@"Id"];
    [searchItems addObject:[[itemDict copy] autorelease]];
  }
  [pickList createSearchItems:searchItems :NSLocalizedString(@"Client",nil)];
  [self.navigationController pushViewController:pickList animated:YES];
  appDelegate.returningID = [NSNumber numberWithInt: projectsClientsId];
  [pool drain];
}

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

  • Строка сразу после цикла for указывает pickList что-то сделать с NSMutableArray. Этот метод должен сохранить новый массив , а также освободить старый массив , если он существует. Если вы просто перезапишите указатель, старый массив будет пропущен. (Кроме того, этот метод плохо назван. Анонимные аргументы (двоеточие без предшествующего текста) являются допустимыми в Objective-C, но считаются крайне плохой практикой. Рассмотрите возможность переименования метода, чтобы лучше выразить, что он делает.)
  • Следующая строка, похоже, связывает список выбора с контроллером навигации. Если это пользовательский код, убедитесь, что метод -pushViewController:animated: правильно освобождает существующий список выбора при указании нового.
  • Предполагается, что присвоение appDelegate.returningID вызывает установщик свойства returningID. Убедитесь, что свойство сохраняет или копирует NSNumber при необходимости.

Утечки памяти бывает сложно отследить, даже в Инструментах, и вы часто обнаружите, что классы Foundation (такие как NSDictionary) протекают как сито, но я всегда мог отследить это вернуться к ненормальности в моем коде. : -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...