2011-05-02 62 views
3

我试图修复当我访问tableView:cellForRowAtIndexPath:indexPath中的NSMutableDictionary时引发的EXC_BAD_ACCESS错误。现在,它的工作原理,当我填写ridesDict与方法loadHistoryFromDBExtended像这样:NSMutableDictionary导致EXC_BAD_ACCESS

self.ridesDict = [self loadHistoryFromDBExtended]; 

NSLog(@"rides dict %@", self.ridesDict); 

不过,我不想叫[自我loadHistoryFromDBExtended]对于每一个细胞都被加载,因为字典也不会改变,所以我尝试移动:

self.ridesDict = [self loadHistoryFromDBExtended]; 

到viewDidLoad中,现在我得到EXC_BAD_ACCESS错误,当我使用:

NSLog(@"rides dict %@", self.ridesDict); 
中的tableView

:的cellForRowAtIndexPath:indexPath。从我看过的内容看来,我有一些内存保留/释放问题,但我似乎无法弄清楚。在loadHistoryFromDBExtended方法被调用后,我尝试在viewDidLoad中使用[self.ridesDict retain],但这并没有帮助。我对此非常陌生,所以我很欣赏任何指向哪里。

编辑:这里是loadHistoryFromDBExtended方法:

-(NSMutableDictionary *)loadHistoryFromDBExtended 
{ 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

    FMDatabase* db = [FMDatabase databaseWithPath:[self getDBPath]]; 

    if (![db open]) 
    { 
     NSLog(@"Could not open db."); 
     [pool release]; 
    } 

    //get users 
    FMResultSet *rs = [db executeQuery:@"SELECT * FROM R order by date desc"]; //query provides result set 

    //create result array 
    NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] init]; 

    while ([rs next]) 
    {   
     NSMutableArray *usersDictArray = [NSMutableArray array]; 

     //look up names for id's 
     [usersDictArray addObject:[rs stringForColumn:@"rNames"]]; 
     [usersDictArray addObject:[rs stringForColumn:@"dName"]]; 
     [usersDictArray addObject:[rs stringForColumn:@"date"]]; 
     [myDictionary setObject:usersDictArray forKey:[rs stringForColumn:@"rID"]]; 

     [usersDictArray release]; 
    } 

    //return usersArray; 
    return myDictionary; 

    [myDictionary release]; 

    [pool drain]; 
} 
+1

'loadHistoryFromDBExtended'是否返回调用者拥有的对象? “ridesDict”的声明是什么?这是一个财产吗?如果是这样,它是“保留”还是“复制”属性?您是否在为该属性使用合成访问器,或者是否实施了自定义访问器? – 2011-05-02 03:14:39

+0

loadHistoryFromDBExtended返回在​​该方法中声明的myDictionary。 ridesDict在接口和@property中声明(nonatomic,retain)NSMutableDictionary * ridesDict;在.h然后@synthesize ridesDict;在.m – 2011-05-02 15:56:36

回答

2

该方法如何实施有许多问题。在检查db是否可以打开时,您释放自动释放池,但继续执行其余代码。我想你可能想在这一点上返回nil。在[rs next]部分中,您将创建一个NSMutableArray,其中+array将创建一个自动释放对象。因此,您不应该致电[usersDictArray release],因为这将会过度释放。 (在每个循环中,“临时”,自动发布的usersDictArray实例将存储在pool自动释放池中。当您调用[pool drain]时,自动释放池将发送所有这些临时实例(release消息)。最后,你有return myDictionary;,这导致未来2行永远不会到达。因此,您创建的autorelease池永远不会被释放(弹出)。

这可能是我将如何实现它:

-(NSMutableDictionary *)loadHistoryFromDBExtended { 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

    FMDatabase* db = [FMDatabase databaseWithPath:[self getDBPath]]; 

    if (![db open]) 
    { 
     NSLog(@"Could not open db."); 
     [pool release]; 
     return nil; // I'm assuming you should return nil here 
    } 

    //get users; query provides result set 
    FMResultSet *rs = [db executeQuery:@"SELECT * FROM R order by date desc"]; 

    //create result array 
    NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] init]; 

    while ([rs next]) 
    {   
     NSMutableArray *usersDictArray = [NSMutableArray array]; 
     //look up names for id's 
     [usersDictArray addObject:[rs stringForColumn:@"rNames"]]; 
     [usersDictArray addObject:[rs stringForColumn:@"dName"]]; 
     [usersDictArray addObject:[rs stringForColumn:@"date"]]; 
     [myDictionary setObject:usersDictArray forKey:[rs stringForColumn:@"rID"]]; 
     // [usersDictArray release]; 
    } 
    [pool drain]; 
    return [myDictionary autorelease]; 
} 

(请注意,我是如何实现这个假设背后创建本地自动释放池的理由是性能,而且有一个地方的全局NSAutoreleasePool吸收最终的[myDictionary autorelease]自动释放对象)。

+0

正如Lou Franco的回复中提到的,这确实解决了问题以及接下来我正在处理的泄漏问题。谢谢。 – 2011-05-02 21:32:14

4

我写这个博客,以帮助理解和调试EXC_BAD_ACCESS

http://loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html

按照容易为了

  1. 运行一个构建和分析 - 你有一个干净的构建?看看它在说什么,但你现在可以忽略泄漏问题 - 寻找将消息发送到已发布对象的问题

  2. 使用NSZombiesEnabled运行 - 这会使对象永不释放,然后在发送消息时发出抱怨一个对象的retainCount为0.

  3. 启用Guard Malloc,然后使用特殊的GDB命令检查堆的完整性。问题在于,您需要在崩溃之前逐步完成并找到真正的问题。它可能会崩溃别的地方更接近你的问题,但

+0

我不知道构建和分析。非常有帮助,谢谢。如果你看到我的原始评论,我添加了loadHistoryFromDBExtended方法,我发布了我用来在每个循环上构建字典的数组。我认为我有一种印象,我必须释放它才能清除阵列,然后重新使用它。我仍然有漏洞,但现在它可以工作,我可以继续前进。再次感谢。 – 2011-05-02 17:03:45

1

尝试致电:

[self.ridesDict retain]; 

使用字典(也许在类初始化)前。不要忘了致电:

[self.ridesDict release]; 
self.ridesDict = nil; 

at dealloc。

另请检查您是否正确声明了标题中的属性。它必须是:

@property (nonatomic, retain) NSMutableArray *ridesDict; 

并将@synthesize ridesDict;添加到您的类实现中。

+0

您需要知道@property是如何声明的,以了解这是否正确。例如,如果是“保留”,则不应该这样做。属性分配会自动保留,并分配给nil,释放旧对象。 – 2011-05-02 11:44:09

+0

但“忘记呼叫保留”这是分段故障(又名EXC_BAD_ACCESS)最常见的原因。同意你的看法,可能是因为你错误地声明了@property。我忘了它是类变量,我认为(我不知道为什么)它是本地变量。但是,如果它是class var,我建议你在@property参数中添加保留 – HiTECNOLOGYs 2011-05-02 12:23:18