iPhone上的内存泄漏:(

时间:2009-06-08 06:40:55

标签: iphone objective-c cocoa-touch memory-management

我是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 个答案:

答案 0 :(得分:9)

返回已分配的NSNumber实例。

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

这一行用另一个NSNumber实例覆盖上面的clientId,numberWithInt返回自动释放的对象,因为你没有为它分配内存,你不应该调用release,它会自动释放。

clientId = [NSNumber numberWithInt:thisClient.clientsId];

您正在调用clientId上的release,因此您会遇到内存问题。 要修复它,请删除上面第一行在这种情况下无用,并将第二行更新为:

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

然后删除:

[clientId release]

因为clientId会自动释放。

编辑:重新出现问题...... 我不确定如何操纵app delegate中的客户端,否则代码应该可以正常工作,我创建了一个小例子,省略了我看不到的部分(app delegate和clients):

//命令行实用程序 - 基础工具项目:

#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;
}

答案 1 :(得分:3)

您正在使用[[NSNumber alloc] init]创建clientID,然后立即使用自动释放的NSNumber实例[NSNumber numberWithInt]覆盖它,然后您将在代码中稍后发布它,这是您不应该做的。摆脱[[NSNumber alloc] init]行和[clientId release]行,这应该稍微修复一下。

答案 2 :(得分:1)

除了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.returningIDreturningID属性调用setter。请确保该财产在必要时保留或复制NSNumber

即使在乐器中,内存泄漏也很难追踪,你会发现它看起来像基础类(如NSDictionary)像筛子一样泄漏,但我一直都能够将其追溯到我的代码中的异常。 : - )