保留或其他原因引起的泄漏? (目标C)

时间:2011-08-05 17:23:59

标签: objective-c ios xcode sqlite

我正在使用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)。

在ViewController.m中

-(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; 

(消息发送到解除分配的实例)。

我一直在撞墙撞墙几天,我真的想从这里前进,所以如果有人能提供帮助,我将非常感激。我还会说,这一切都是学习经历,所以在某些情况下,如果你不得不问“你为什么这样做?”答案可能是“因为我很蠢”。希望这里的问题对某些人来说很明显。

6 个答案:

答案 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?