2011-04-18 186 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

相關問題