2011-08-24 118 views
0

我面臨分配對象的潛在泄漏。那麼如何在循環中釋放我的自定義類對象。下面附上我的代碼。對象的潛在泄漏

- (ProfileClass *) getUserProfile 

{

NSString *query = [NSString stringWithFormat:@"SELECT * FROM Profile"]; 
NSLog(@"query %@",query); 

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
NSString *documentsDirectory = [paths objectAtIndex:0]; 
NSString *path = [documentsDirectory stringByAppendingPathComponent:@"MOFAdb.sqlite"]; 
ProfileClass *profile = nil; 
// Open the database. The database was prepared outside the application. 
if(sqlite3_open([path UTF8String], &database) == SQLITE_OK) 
{ 

    sqlite3_stmt *Statement1; 
    //int i=0; 
    if (sqlite3_prepare_v2(database, [query UTF8String], -1, &Statement1, NULL) == SQLITE_OK) { 

     //int returnValue = sqlite3_prepare_v2(database, sql, -1, &Statement1, NULL); 
     if (sqlite3_step(Statement1) == SQLITE_ROW) { 
      // The second parameter indicates the column index into the result set. 

      NSString *userName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(Statement1, 0)]; 
      NSString *userEmail = [NSString stringWithUTF8String:(char *)sqlite3_column_text(Statement1, 1)]; 
      NSString *phoneNum = [NSString stringWithUTF8String:(char *)sqlite3_column_text(Statement1, 2)]; 
      //int phone = sqlite3_column_int(Statement1, 2); 
      //NSLog(@"%d",phone); 

      //RecipeClass *rc = [[RecipeClass alloc] getRecipe:recipeName withRecipeIng:recipeIng withRecipeInst:recipeInstru withRecipeTips:recipeTips withRecipeDesc:recipeDesc]; 

      if (profile) 
       [profile release]; 

      profile = [[ProfileClass alloc] getProfileInfo:userName withEmail:userEmail withPhone:phoneNum]; 

      //NSLog(@"%@",fact); 
      //NSLog(@"%d",i); 
      //i++;  

     } 
    } 

    //Release the select statement memory. 
    sqlite3_finalize(Statement1); 
    //} 
} 
else { 
    // Even though the open failed, call close to properly clean up resources. 
    sqlite3_close(database); 
    NSAssert1(0, @"Failed to open database with message '%s'.", sqlite3_errmsg(database)); 
    // Additional error handling, as appropriate... 
} 

return profile; 

}

如果我自動釋放我的個人資料= [[[ProfileClass的alloc] getProfileInfo:用戶名withEmail:USEREMAIL withPhone:PHONENUM]自動釋放];所以我的應用程序崩潰了。所以我發佈如果檢查,但建立和分析顯示它作爲一個警告。

+0

呃,你有在任何地方有'init'調用嗎? – jtbandes

+0

您需要發佈'getProfileInfo:withEmail:withPhone:'的代碼。 – Yuji

+0

正如你總是從這個ProfileClass * profile = nil;下面的代碼將永遠不會執行如果(profile) [profile release]; – Saran

回答

1

您也可以自動釋放這樣的:

返回[配置文件自動釋放]

並保留ProfileClass在要用它的對象,

EX- ProfileClass * objProfile = [[數據庫getUserProfile]保留];

並在您使用它時釋放objProfile。

+0

但不是它與我的返回相同[[profile autorelease] retain]; ?? – user366584

+0

不,它不一樣,因爲如果你保留任何意味着你是該對象的所有者的對象。只有你可以發佈它,所以你不能在其他課堂上發佈它。 –

0

你爲什麼不這樣做:

return [profile autorelease]; 

而且沒有必要的

if (profile) 

檢查。只需release無條件。如果profile爲零,則不會有任何負面影響。


FWIW:我不太明白你的getProfile:etc...方法是做什麼的。我認爲這是一個初始化器,僅此而已(就像可可中的許多initXYZ:方法)。如果是這樣,你應該把它叫做initWithUserName:email:phone:以符合約定。你可以發佈該方法嗎?

+0

我解決它作爲返回[[任務autorelease]保留]; – user366584

+0

@ user366584只是b/c你的錯誤消失並不意味着你解決了它。在給出建議之前閱讀內存管理。你用[[autorelease]保留]做了什麼;是錯的。您保留一個您正在自動釋放的對象。背後的原因是什麼?它接近了我,你只是盲目地解決問題,只需輸入與內存管理相關的任何內容。 – Cyprian

+0

@ user366584:Cyprian是對的。 「它有效」並不意味着你所做的是正確的。在這種情況下,它沒有任何意義。什麼是'使命'? –

0

使用數組,你可以調用此方法

NSMutableArray *ProfileArray=[[NSMutableArray alloc] initWithArray:[ClassObj getUserProfile]]; 
ProfileClass *profileObj=[[ProfileArray objectAtIndex:0] retain]; 
[ProfileArray release]; 
// now you can use profile object anywhere... I hope memory issue is also solved 



- (NSMutableArray *) getUserProfile 

{ 
    NSMutableArray *array=[[NSMutableArray alloc] init]; 

NSString *query = [NSString stringWithFormat:@"SELECT * FROM Profile"]; 
NSLog(@"query %@",query); 

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
NSString *documentsDirectory = [paths objectAtIndex:0]; 
NSString *path = [documentsDirectory stringByAppendingPathComponent:@"MOFAdb.sqlite"]; 
ProfileClass *profile = nil; 
// Open the database. The database was prepared outside the application. 
if(sqlite3_open([path UTF8String], &database) == SQLITE_OK) 
{ 

    sqlite3_stmt *Statement1; 
    //int i=0; 
    if (sqlite3_prepare_v2(database, [query UTF8String], -1, &Statement1, NULL) == SQLITE_OK) { 

     //int returnValue = sqlite3_prepare_v2(database, sql, -1, &Statement1, NULL); 
     if (sqlite3_step(Statement1) == SQLITE_ROW) { 
      // The second parameter indicates the column index into the result set. 

      NSString *userName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(Statement1, 0)]; 
      NSString *userEmail = [NSString stringWithUTF8String:(char *)sqlite3_column_text(Statement1, 1)]; 
      NSString *phoneNum = [NSString stringWithUTF8String:(char *)sqlite3_column_text(Statement1, 2)]; 
      //int phone = sqlite3_column_int(Statement1, 2); 
      //NSLog(@"%d",phone); 

      //RecipeClass *rc = [[RecipeClass alloc] getRecipe:recipeName withRecipeIng:recipeIng withRecipeInst:recipeInstru withRecipeTips:recipeTips withRecipeDesc:recipeDesc]; 

      if (profile) 
       [profile release]; 

      profile = [[ProfileClass alloc] getProfileInfo:userName withEmail:userEmail withPhone:phoneNum]; 
     [array addObject:profile]; 
     [profile release]; 


     } 
    } 

    //Release the select statement memory. 
    sqlite3_finalize(Statement1); 
    //} 
} 
else { 
    // Even though the open failed, call close to properly clean up resources. 
    sqlite3_close(database); 
    NSAssert1(0, @"Failed to open database with message '%s'.", sqlite3_errmsg(database)); 
    // Additional error handling, as appropriate... 
} 

return [array autorelease]; 

} 

我希望這將有助於你 歡呼

之前解決這個問題
0

你的方法:- (ProfileClass *) getUserProfile不是一個實例方法或副本,應該返回一個自動發佈的對象。但是你應該在最後一行做到這一點,因爲你有一個if/else結構,並且如果你只是在線上自動釋放它,它不會在if語句失敗並轉到其他語句時自動釋放。因此,只要做到這一點:

return [profile autorelease]; 
+0

FWIW是同一個實例變量,它是一個實例方法,因爲它在一個分配的實例上運行。這可能只是一個名稱錯誤的初始值設定項。 –

+0

@Cyprian它崩潰了,所以這就是爲什麼我在上面的評論中提出了一個解決方案,但它不是正確的內存管理 – user366584