MattStacey
MattStacey

Reputation: 895

iOS - object sent autorelease too many times

I have a method that is reading some information from a sqlite db and initialising a class called Achievement. When I analyse this code I am given the feedback 'object sent autorelease too many times'. I don't really understand where I am going wrong - why is the retval object released on line 225 and not at the return statement on line 229?

Can someone please explain where I have made a mistake in the code below and how I can fix it?

Function Code (so answerer can easily copy/paste):

- (Achievement *)getAchievement:(int)Id

{

Achievement *retval = [[Achievement alloc] autorelease];

NSString *query = [NSString stringWithFormat:@"SELECT * FROM Achievements where ID = %d", Id];

sqlite3_stmt *statement;

if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, nil)
    == SQLITE_OK) {
    while (sqlite3_step(statement) == SQLITE_ROW) {
        int Id = sqlite3_column_int(statement, 0);
        char *name = (char *) sqlite3_column_text(statement, 1);
        char *title  = (char *) sqlite3_column_text(statement, 2);
        char *description = (char *) sqlite3_column_text(statement, 3);

        Boolean Achieved;
        char *com = (char *) sqlite3_column_text(statement, 4);
        NSString *c1 = [[[NSString alloc] initWithUTF8String:com] autorelease];
        Achieved = [c1 isEqualToString:@"1"];

        NSDate *CompletedDate = (NSDate *) sqlite3_column_text(statement, 5);

        char *icon = (char *) sqlite3_column_text(statement, 6);

        int New = sqlite3_column_int(statement, 7);

        NSString *Title = [[[NSString alloc] initWithUTF8String:title] autorelease];
        NSString *Description = [[[NSString alloc] initWithUTF8String:description] autorelease];
        NSString *Name = [[[NSString alloc] initWithUTF8String:name] autorelease];
        NSString *Icon = [[[NSString alloc] initWithUTF8String:icon] autorelease];

        retval = [retval initDetails:Id :Name :Title: Description : Achieved : CompletedDate: Icon: New];
    }
    sqlite3_finalize(statement);
}
return retval;

}

Analysis feedback image: enter image description here

As always any feedback is greatly appreciated.

Upvotes: 0

Views: 1327

Answers (2)

Max
Max

Reputation: 16709

Achievement *retval = [[Achievement alloc] autorelease];

this is very bad idea to do that. You ALWAYS have to initialize object before using it. Instead you're initializing it in a loop:

retval = [retval initDetails:Id :Name :Title: Description : Achieved : CompletedDate: Icon: New];

I don't really get why you need to initialize the same object multiple times. Maybe, you need to create multiple objects and init them with different values?

Rearrange this:

Achievement *retval = nil;
while (...) {
    [retval release];
    retval = [[Achievement alloc] initDetails: ...];
}
return [retval autorelease];

Upvotes: 2

Costique
Costique

Reputation: 23722

I guess you're confusing the compiler with the wrong sequence of alloc, init, autorelease. What you should be doing instead is the following (pseudocode):

Achievement *retval = nil;
while (...) {
    retval = [[[Achievement alloc] initDetails: ...] autorelease];
}
return retval;

Upvotes: 1

Related Questions