我正在使用Leaks,我相信我已经缩小了问题范围,而且我确信我的经验不足与它有关。如果您发现我的逻辑失败(例如,显然有一种更简单的方法),请告诉我。
在这种情况下,我们使用3个类,一个描述数据库中行的Row类,一个包含getRow的数据库类,insertRow类型函数和一个ViewController类。
在Row.h中:
@interface Row : NSObject {
int rowID;
NSString *FirstName;
NSString *LastName;
}
@property (nonatomic) int rowID;
@property (nonatomic, retain) NSString *FirstName; <--see comments below
@property (nonatomic, retain) NSString *LastName; <--see comments below
@end
希望这个很明显,创建一个对象,我将把数据从数据库中拉出来。
在Database.m中
-(Row *) getRow {
NSLog(@"Inside getRow");
Row *holder = [[[Row alloc] init] autorelease];
...All the SQL stuff... (Select * from table where id = 1), etc.
char *first = (char *)sqlite3_column_text(statement, 1);
char *last = (char *)sqlite3_column_text(statement, 2);
holder.rowID = sqlite3_column_int(statement, 0);
holder.FirstName = [NSString stringWithUTF8String:first];
holder.LastName = [NSString stringWithUTF8String:last];
return holder;
}
另外,希望,相当自我解释。从数据库中获取特定行,将信息放入Row对象(参见Row.h)。
-(void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
dataB = [[Database alloc] init];
[dataB openDB];
currentRow = [[dataB getRow] retain]; <--See comments below.
firstNameLabel.text = currentRow.FirstName;
}
-(IBAction)btnGetLastName:(id)sender{
lastNameLabel.text = currentRow.LastName; <--See comments below.
[currentRow release];
currentRow = [dataB getRow];
}
此处视图控制器基本上为您提供名字,当您单击按钮时,它会显示姓氏。
所以,我正在泄漏,每次按btnGetLastName时我都会缩小范围。如果我不保留
currentRow = [[dataB getRow] retain];
我崩溃了
lastNameLabel.text = currentRow.LastName;
(消息发送到解除分配的实例)。
我一直在撞墙撞墙几天,我真的想从这里前进,所以如果有人能提供帮助,我将非常感激。我还会说,这一切都是学习经历,所以在某些情况下,如果你不得不问“你为什么这样做?”答案可能是“因为我很蠢”。希望这里的问题对某些人来说很明显。
答案 0 :(得分:2)
好吧,我在这里看到的一些事情是不正确的。首先,您应该将currentRow
作为保留属性,这样您就不必保留它并自行释放它。另外,请确保您的Row类的-dealloc
方法如下所示:
- (void)dealloc {
self.FirstName = nil;
self.LastName = nil;
[super dealloc];
}
让你的currentRow成为这样的属性:
@property (nonatomic, retain) Row * currentRow;
然后,将其指定为self.currentRow = aRow
。另请注意,您还需要在dealloc方法中设置self.currentRow = nil
。您的应用很可能会崩溃,因为您没有在currentRow = [dataB getRow];
行保留currentRow。
我还想指出,将实例变量的第一个字母大写是不好的惯例。
答案 1 :(得分:1)
在行dealloc方法中,您是否释放FirstName和LastName?
这似乎是你所描述的过度保留的显而易见的地方。因为你在做holder.FirstName = [NSString stringWithUTF8String:first];
,所以你正在使用合成的setter进行保留。如果你没有在dealloc()中显式释放,那么FirstName和LastName将最终徘徊。
答案 2 :(得分:0)
currentRow = [[dataB getRow] retain];
是对的。如果你做self.currentRow = [dataB getRow],(其中currentRow是一个保留的合成属性),那也是正确的。直接访问成员变量时,您正在绕过合成属性设置器执行分配。
答案 3 :(得分:0)
在getRow
内,您不释放sqlite3_
函数返回的char数组。这至少应该是两次泄漏。
如果你没有保留currentRow
,那么崩溃是相反的:它会被释放,但在你完成它之前,必须保留它以避免这种情况,同样在btnGetLastName
。请务必在dealloc
。
答案 4 :(得分:0)
在第一次调用getRow
时,您保留结果(如您所愿)。然后按下按钮时,将其释放。目前很好。然后再次getRow
,但不要保留它。
答案 5 :(得分:0)
在自动释放对象上执行发布时可能存在问题。所以我会这样做: Row * holder = [[row alloc] init];
我相信你在你的dealloc方法中释放currentRow?