user366584
user366584

Reputation: 1056

Potential Leak of an object

I am facing Potential leak of an object allocated. So how can I release my custom class object in loop . I am enclosing my code below herewith.

- (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; 

}

If I autorelease my profile = [[[ProfileClass alloc] getProfileInfo:userName withEmail:userEmail withPhone:phoneNum] autorelease]; so my application crashes later. So I m release on if check but build and Analyze shows it as a warning.

Upvotes: 0

Views: 380

Answers (4)

Srinivas
Srinivas

Reputation: 983

using an array you can solve this issue before calling this method

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]; 

}

I hope it will be helpful to you cheers

Upvotes: 0

Rudy Velthuis
Rudy Velthuis

Reputation: 28806

Why don't you do:

return [profile autorelease];

And there is no need for the

if (profile)

check. Just release unconditionally. If profile is nil, it won't have any negative effect.


FWIW: I don't quite understand what your getProfile:etc... method does. I assume it is an initializer and nothing more (like the many initXYZ: methods in Cocoa). If so, you should probably call it initWithUserName:email:phone: to go with the convention. Could you post the method?

Upvotes: 0

alok chauve
alok chauve

Reputation: 582

You can also autorelease like that:

return [profile autorelease];

and retain the object of ProfileClass where you used it,

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

and release objProfile when you used it.

Upvotes: 1

Cyprian
Cyprian

Reputation: 9453

Your method: - (ProfileClass *) getUserProfile is not an instance method or a copy you should return an object that is autoreleased. But you should do it on the last line, since you have a if/else structure and if you only autorelease it on line profile = [[[ProfileClass alloc] getProfileInfo:userName withEmail:userEmail withPhone:phoneNum] autorelease]; it will not get autoreleased if it fails the if statement and goes to else. So just do this:

return [profile autorelease];

Upvotes: 0

Related Questions