物体的潜在泄漏

时间:2011-08-24 07:25:40

标签: iphone objective-c ios ios4

我正面临分配对象的潜在泄漏。那么如何在循环中释放我的自定义类对象。我随函附上我的代码。

- (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:userName withEmail:userEmail withPhone:phoneNum] autorelease];所以我的应用程序后来崩溃了。所以我发布如果检查,但build和Analyze将其显示为警告。

4 个答案:

答案 0 :(得分:1)

你也可以这样自动释放:

return [profile autorelease];

并保留使用它的ProfileClass对象,

Ex- ProfileClass * objProfile = [[database getUserProfile] retain];

并在使用它时释放objProfile。

答案 1 :(得分:0)

你为什么不这样做:

return [profile autorelease];

并且不需要

if (profile)

检查。只是release无条件。如果profile为零,则不会产生任何负面影响。


FWIW:我不太明白你的getProfile:etc...方法做了什么。我假设它是一个初始化器,仅此而已(就像Cocoa中的许多initXYZ:方法)。如果是这样,您应该将其称为initWithUserName:email:phone:以符合惯例。你能发布这个方法吗?

答案 2 :(得分: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]; 

}

我希望它会对你有所帮助 欢呼声

答案 3 :(得分:0)

您的方法:- (ProfileClass *) getUserProfile不是实例方法或副本,您应该返回自动释放的对象。但是你应该在最后一行完成,因为你有一个if / else结构,如果你只在行profile = [[[ProfileClass alloc] getProfileInfo:userName withEmail:userEmail withPhone:phoneNum] autorelease];上自动释放它,如果if语句失败并转到else,它将不会被自动释放。所以这样做:

return [profile autorelease];