2011-04-18 184 views
0

我有一个NSMutableArray这样定义的:xCode - 为什么这个内存泄漏?

@property (nonatomic, retain)   NSMutableArray   *cList; 

我已妥善安置在我的dealloc释放到CLIST,并选择我从数据库中retrive一些数据:

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对象。

回答

3

的代码

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 array]返回一个自动释放的可变数组。通过将其设置为您的retain属性,您可以获得一次所有权。

此外,另一个小点,没有必要检查,看看你的财产是否为零。如果你想删除一个属性,只需做self.cList = nil;。运行时将为您处理释放变量;这是使用@properties的重要原因之一。

+0

像你说的取代消除了所有的泄漏。谢谢。但你能解释我为什么泄漏吗? – CristiC 2011-04-18 15:28:43

+0

第二块中的警告源于相同的根本原因。因为newM被添加到cList,所以当cList泄漏时它也会泄漏。 – 2011-04-18 15:30:12

1

对'alloc'的调用返回拥有(即+1)引用。当您将其分配给“保留”属性时,您将增加保留计数,并给出+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]; 

所以在你使用自动释放地说,对象应在未来自动释放,如果你不以其他方式留住他们这两种情况下 - 你凭借做(保留)属性并添加到NSArray中。

+0

我还没有测试,但像你说的那样:self.cList = [[[[[NSMutableArray alloc] init] autorelease];不会释放我的cList让我们说在选择器的末尾?并且稍后可以在我的应用程序中使用它吗? – CristiC 2011-04-18 15:33:02

+0

当您回到运行循环时,cList将被autorelease池释放一次。但是你做了同样的事情,保留了两次 - 一次是由于'alloc',一次是由于'retain'属性。 Objective-C点语法调用setter,即使它看起来像C风格的struct成员值赋值。两个保留+一个释放=正确的所有权计数。 – Tommy 2011-04-18 19:22:02

相关问题