2009-06-08 144 views
1

我是C,Obj-C和iPhone的初学者,我正在尝试使用很多术语,希望你们能帮助解决问题。现在已经挣扎了几天在iPhone上泄漏内存:(

我的代码是调用一个包含一个搜索字段和一个表的nib的方法,该表从下面为'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]; 

} 

提前感谢!

回答

9

这将返回分配的NSNumber实例。

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

这条线覆盖与NSNumber的另一个实例以上的clientId,自动释放的对象,因为你还没有为它分配的内存,你不应该释放呼叫numberWithInt返回时,它会自动释放。

clientId = [NSNumber numberWithInt:thisClient.clientsId]; 

您正在调用clientId上的release版本,因此会出现内存问题。 要修复它除去第一线之上即在该情况下无用并更新第二个到:

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

然后取出:

[clientId release] 

由于的clientId将被自动解除。

编辑:重新仍然有问题...... 我不知道怎么给你操纵的应用程序委托的客户,否则代码应工作正常,我创建了小例子,省略了,我可以在部分”看不到(应用程序委托和客户端):

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

#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

谢谢你的时间!我确实按照你的建议使用了它,但改变了代码,认为它可以解决问题。现在它按照你的建议回来了,但是泄漏结果相同。我能否认为问题出在被调用的笔尖之内? – Chris 2009-06-08 07:52:25

3

您正在创建clientID [[NSNumber alloc] init],然后立即用自动发布的NSNumber实例[NSNumber numberWithInt]覆盖它,然后稍后在您的代码中发布它,您不应该这样做。摆脱[[NSNumber alloc] init]线和[clientId release]线,并应该修复它一点。

+0

非常感谢您的回答。我确实按照你的建议使用了它,但改变了代码,认为它可以解决问题。现在它按照你的建议回来了,但是泄漏结果相同。我能否认为问题出在被调用的笔尖之内? – Chris 2009-06-08 07:52:29

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.returningID被假定为调用者调用returningID属性。确保财产根据需要保留或复制NSNumber

内存泄漏可能会非常棘手追查,即使在仪器,你经常会发现它看起来像基础类(如NSDictionary)正在泄漏像筛子,但我一直能追踪到它回到我的代码中的异常。 :-)