xCode-为什么会出现内存泄漏?
我有一个NSMutableArray,定义如下:xCode-为什么会出现内存泄漏?,xcode,memory-leaks,nsmutablearray,Xcode,Memory Leaks,Nsmutablearray,我有一个NSMutableArray,定义如下: @property (nonatomic, retain) NSMutableArray *cList; 我已经在我的dealloc中正确地放置了对cList的发布,并在选择器中从数据库中检索了一些数据: sqlite3 *database; if(sqlite3_open([self.filePath UTF8String], &database) == SQLITE_OK) { N
@property (nonatomic, retain) NSMutableArray *cList;
我已经在我的dealloc中正确地放置了对cList的发布,并在选择器中从数据库中检索了一些数据:
sqlite3 *database;
if(sqlite3_open([self.filePath UTF8String], &database) == SQLITE_OK) {
NSString *sqlStatement = [NSString stringWithFormat:@".....", self.someData];
sqlite3_stmt *compiledStatement;
if (self.cList != nil) {
[self.cList release];
self.cList = nil;
}
self.cList = [[NSMutableArray alloc] init];
if(sqlite3_prepare_v2(database, [sqlStatement UTF8String], -1, &compiledStatement, NULL) == SQLITE_OK) {
sqlite3_bind_text(compiledStatement, 1, [self.someString UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(compiledStatement, 2, [self.someOtherString UTF8String], -1, SQLITE_TRANSIENT);
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
MyModel *newM = [[MyModel alloc] init];
newM.d = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 0)];
newM.c = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 1)];
newM.i = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 2)];
[self.cList addObject:newM];
[newM release];
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
当我使用仪器运行时,它向我显示了以下线路中的一些泄漏:
self.cList = [[NSMutableArray alloc] init];
...
MyModel *newM = [[MyModel alloc] init];
newM.d = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 0)];
newM.c = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 1)];
newM.i = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 2)];
[self.cList addObject:newM];
使用泄漏的对象:NSCFString和MyModel。为什么?我已经正确地释放了cList对象。这段代码
if (self.cList != nil) {
[self.cList release];
self.cList = nil;
}
self.cList = [[NSMutableArray alloc] init];
完全可以由以下内容替代:
self.cList = [NSMutableArray array];
这将消除第一次泄漏。不知道为什么在第二个代码块上会出现泄漏警告,因为您正确地发布了newM
代码泄漏是因为您正在创建一个对象并获取其所有权(
[[NSMutableArray alloc]init]
),然后将该对象设置为retain
属性,再次获取该对象的所有权。理论上,您可以通过调用release
两次来解决这个问题,但这很愚蠢<代码>[NSMutableArray]返回一个自动释放的可变数组。通过将其设置为您的retain
属性,您可以一次性获得它的所有权
另外,还有一个小问题,不需要检查您的属性是否为零。如果要删除属性,只需执行self.cList=nil代码>。运行时将为您释放变量;这是使用@properties的重要原因之一。这段代码
if (self.cList != nil) {
[self.cList release];
self.cList = nil;
}
self.cList = [[NSMutableArray alloc] init];
完全可以由以下内容替代:
self.cList = [NSMutableArray array];
这将消除第一次泄漏。不知道为什么在第二个代码块上会出现泄漏警告,因为您正确地发布了newM
代码泄漏是因为您正在创建一个对象并获取其所有权([[NSMutableArray alloc]init]
),然后将该对象设置为retain
属性,再次获取该对象的所有权。理论上,您可以通过调用release
两次来解决这个问题,但这很愚蠢<代码>[NSMutableArray]
返回一个自动释放的可变数组。通过将其设置为您的retain
属性,您可以一次性获得它的所有权
另外,还有一个小问题,不需要检查您的属性是否为零。如果要删除属性,只需执行
self.cList=nil代码>。运行时将为您释放变量;这是使用@properties的一个重要原因。调用'alloc'返回一个拥有的(即+1)引用。将其指定给“retain”属性时,将增加retain计数,即+2。因此,当您稍后释放它时,它将以+1的保留计数泄漏。同样,当您将newM添加到cList时,它会再次被保留,即使您已经拥有它
建议的改动:
self.cList = [[[NSMutableArray alloc] init] autorelease]; // or [NSMutableArray array]
...
MyModel *newM = [[[MyModel alloc] init] autorelease];
newM.d = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 0)];
newM.c = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 1)];
newM.i = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 2)];
[self.cList addObject:newM];
因此,在这两种情况下,您都在使用autorelease来表示,如果您不保留对象,则将来应该自动释放这些对象—这是通过(retain)属性和添加到NSArray来实现的。对“alloc”的调用返回一个拥有的(即+1)引用。将其指定给“retain”属性时,将增加retain计数,即+2。因此,当您稍后释放它时,它将以+1的保留计数泄漏。同样,当您将newM添加到cList时,它会再次被保留,即使您已经拥有它
建议的改动:
self.cList = [[[NSMutableArray alloc] init] autorelease]; // or [NSMutableArray array]
...
MyModel *newM = [[[MyModel alloc] init] autorelease];
newM.d = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 0)];
newM.c = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 1)];
newM.i = [NSString stringWithUTF8String:(char *) sqlite3_column_text(compiledStatement, 2)];
[self.cList addObject:newM];
因此,在这两种情况下,您都使用autorelease来表示,如果您不保留对象,则将来应该自动释放这些对象—这是通过(保留)属性和添加到NSArray中实现的。按照您所说的进行替换可以消除所有泄漏。谢谢但是你能解释一下它为什么会泄漏吗?第二个区块中的警告源于同一个根本原因。因为newM被添加到cList中,所以当cList泄漏时它也会泄漏。正如您所说的,替换可以消除所有泄漏。谢谢但是你能解释一下它为什么会泄漏吗?第二个区块中的警告源于同一个根本原因。因为newM被添加到cList中,所以当cList泄漏时,它也会泄漏。我还没有测试,但按照您说的做:self.cList=[[[NSMutableArray alloc]init]autorelease];不会在选择器的末尾释放我的cList吗?以后在我的应用程序中是否可以使用它?当你回到运行循环时,自动释放池会释放一次cList。但是你做了两次与保留它相同的事情——一次是因为“alloc”,一次是因为“retain”属性。Objective-C点语法调用setter,即使它看起来像C风格的结构成员值赋值。两个保留+一个发布=正确的所有权计数。我还没有测试,但按照你说的做:self.cList=[[NSMutableArray alloc]init]autorelease];不会在选择器的末尾释放我的cList吗?以后在我的应用程序中是否可以使用它?当你回到运行循环时,自动释放池会释放一次cList。但是你做了两次与保留它相同的事情——一次是因为“alloc”,一次是因为“retain”属性。Objective-C点语法调用setter,即使它看起来像C风格的结构成员值赋值。两个保留+一个发布=正确的所有权计数。