我正在尝试修复当我在tableView中访问NSMutableDictionary时抛出的EXC_BAD_ACCESS错误:cellForRowAtIndexPath:indexPath。现在,当我使用方法loadHistoryFromDBExtended填充ridesDict时,它可以正常工作:
self.ridesDict = [self loadHistoryFromDBExtended];
NSLog(@"rides dict %@", self.ridesDict);
但是,我不想为每个正在加载的单元调用[self loadHistoryFromDBExtended],因为字典不会改变,所以我尝试移动:
self.ridesDict = [self loadHistoryFromDBExtended];
to 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];
}
答案 0 :(得分:4)
我写这篇博客是为了帮助理解和调试EXC_BAD_ACCESS
http://loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html
为了方便
运行构建和分析 - 你得到一个干净的构建?看看它在说什么,但你现在可以忽略泄漏问题 - 寻找向已发布对象发送消息的问题
使用NSZombiesEnabled运行 - 这会使对象永远不会释放,然后在向retainCount为0的对象发送消息时进行投诉。
启用Guard Malloc,然后使用特殊的GDB命令检查堆的完整性。问题是你需要在崩溃之前单步执行此操作以找到真正的问题。尽管
答案 1 :(得分:2)
该方法的实施方式存在诸多问题。在检查是否可以打开db
时,释放自动释放池,然后继续执行其余代码。我想你可能希望在那时返回nil
。在[rs next]
部分中,您使用NSMutableArray
创建+array
,这会创建一个自动释放的对象。因此,您不应该调用[usersDictArray release]
,因为这会过度释放。 (在每个循环中,“临时”,自动释放的usersDictArray
实例将存储在pool
自动释放池中。当您调用[pool drain]
时,自动释放池将发送所有这些临时实例a release
消息)。接近最后,你有return myDictionary;
,这导致永远无法达到接下来的两行。因此,您创建的自动释放池永远不会被释放(弹出)。
这可能是我实施它的方式:
-(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]
自动释放对象)。
答案 2 :(得分:1)
尝试致电:
[self.ridesDict retain];
在使用字典之前(可能在init类)。别忘了打电话:
[self.ridesDict release];
self.ridesDict = nil;
at dealloc。
同时检查是否正确声明了标题中的属性。必须是:
@property (nonatomic, retain) NSMutableArray *ridesDict;
并将@synthesize ridesDict;
添加到您的类实现中。