2009-06-08 2 views
1

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

Мой код ниже - это метод, который вызывает нить, содержащую поле поиска и таблицу. Таблица заполняется поиском массива, созданного для «theList» ниже. Используя «Инструменты», я получаю утечку на линии: NSDictionary * theItem = [Словарь NSDictionaryWithObjectsAndKeys: 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]; 

} 

Заранее благодарен!

ответ

9

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

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

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

clientId = [NSNumber numberWithInt:thisClient.clientsId]; 

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

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

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

[clientId release] 

Поскольку ClientId будет выпущен автоматически.

EDIT: 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; 
} 
+0

Спасибо за ваше время! Я действительно имел это, как вы предлагаете, но изменил этот код, думая, что он может решить проблему. Теперь он вернулся, как вы предполагали, но с теми же результатами утечки. Могу ли я считать, что проблема лежит в названном nib? – Chris

+0

Какова ошибка, которую вы получаете? – stefanB

+0

Существует несколько ... NSCFDictionary, NSCFArray & GeneralBlock-16 и ссылка на эту одну строку. Как вы видите, я нажимаю новый ViewController в конце метода - там я создаю два MutableArrays с помощью MutableCopy для выполнения поиска TableView - я не выполняю глубокую копию, поэтому я предполагаю, что MutableCopies все еще связаны с те же пары объектов ?. Эти два массива, очевидно, выпущены в пределах ViewController после завершения. Еще раз спасибо за ваше время и помощь. – Chris

3

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

+0

Большое спасибо за ваш ответ. Я действительно имел это, как вы предлагаете, но изменил этот код, думая, что он может решить проблему. Теперь он вернулся, как вы предполагали, но с теми же результатами утечки. Могу ли я считать, что проблема лежит в названном nib? – Chris

1

Помимо очевидной утечки из NSNumber, есть несколько других вещей, которые я бы исправить, что может помочь. Большинство из них довольно незначительные, но, по моему опыту с Objective-C, менее code == clearer, что-то, что не одинаково верно для таких языков, как 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]; 
} 

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

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

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

Смежные вопросы