xCode-为什么会出现内存泄漏?

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

我有一个NSMutableArray,定义如下:

@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风格的结构成员值赋值。两个保留+一个发布=正确的所有权计数。