views:

280

answers:

5

I am using the following function in my application:

+(TeamTournamentLookUp  *)getOpponentTeamTournamentLookUp:(int)tournamentId:(int)opponentTeamId
{
    TeamTournamentLookUp *objOpponentTTL = nil;
    const char *sql = "SELECT TeamTournamentLookUpID, TournamentID, TeamID, NumberOfWins, NumberOfLosses, NumberOfDraws, Points, Rank, IsUserTeam from TeamTournamentLookUp where TournamentID = ? and TeamID = ?";
    sqlite3_stmt *selectstmt;
    if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) != SQLITE_OK) 
 NSAssert1(0, @"Error. '%s'", sqlite3_errmsg(database));

    sqlite3_bind_int(selectstmt, 1, tournamentId);
    sqlite3_bind_int(selectstmt, 2, opponentTeamId);

    if(SQLITE_DONE != sqlite3_step(selectstmt))
    {
     NSInteger primaryKey = sqlite3_column_int(selectstmt, 0);
     objOpponentTTL = [[TeamTournamentLookUp alloc] initWithPrimaryKey:primaryKey];
     objOpponentTTL.tournamentId = sqlite3_column_int(selectstmt, 1);
     objOpponentTTL.teamId = sqlite3_column_int(selectstmt, 2);
     objOpponentTTL.numberOfWins = (sqlite3_column_type(selectstmt, 3) == SQLITE_NULL) ? 0 : sqlite3_column_int(selectstmt, 3);
     objOpponentTTL.numberOfLosses = (sqlite3_column_type(selectstmt, 4) == SQLITE_NULL) ? 0 : sqlite3_column_int(selectstmt, 4);
     objOpponentTTL.numberOfDraws = (sqlite3_column_type(selectstmt, 5) == SQLITE_NULL) ? 0 : sqlite3_column_int(selectstmt, 5);
     objOpponentTTL.points = (sqlite3_column_type(selectstmt, 6) == SQLITE_NULL) ? 0 : sqlite3_column_int(selectstmt, 6);
     objOpponentTTL.rank = (sqlite3_column_type(selectstmt, 7) == SQLITE_NULL) ? 0 : sqlite3_column_int(selectstmt, 7);
  objOpponentTTL.isUserTeam = (sqlite3_column_type(selectstmt, 9) == SQLITE_NULL) ? 0 : sqlite3_column_int(selectstmt, 9);
    }

    return objOpponentTTL;
}

Basically I am returning an Object of TeamTournamentLookUp class.

In the code I am allocating the object: objOpponentTTL = [[TeamTournamentLookUp alloc] initWithPrimaryKey:primaryKey];

Now my question is where should I release the object?

+3  A: 

If you are writing for Objective C 2 then you don't need to do more code just build with garbage collection. If for earlier versions including iPhone then you would need to release it at some stage.

In this case the usual way is to autorelease it when you create it. e.g.

objOpponentTTL = [[[TeamTournamentLookUp alloc] initWithPrimaryKey:primaryKey]autorelease];

The object will be released when you reach an autorelease pool. There is one of these by default in NSApplication and gets called in the input loop.

For more on memory management read Apple's docs on memory management

Mark
+2  A: 

Send it the autoRelease message before you return it. This way it'll get a release message sent to it, but not just yet.

Then whatever is calling your method will have to retain the object that's returned.

You can look up the patterns for handling retain, release, autoRelease in the Apple documentation. It's very handy to learn some basic rules.

Tom Duckering
+1  A: 

Using objective-c, technically your function should autorelease your returned object, eg.

return [autorelease objOpponentTTL];

The calling object should retain the returned object eg.

TeamTournamentLookUp * object = [[self getOpponentTeamTournamentLookUp:5:6] retain];

When you are finished using 'object', you should release it then ie.

[object release]

I haven't really used Objective-C 2.0 and its garbage collection, so I'm not sure what the syntax should be if you have garbage collection turned on. However, if you're using standard Objective-C, then this should be fine for you.

Without garbage collection, the convention is to retain an object when you want to use it, and release it when you're finished with it. If you were to add 'object' to a container (eg. an NSMutableArray), the function you're calling will retain the object, and you can safely release it after adding to the collection, eg.

....
TeamTournamentLookUp * object = [[self getOpponentTeamTournamentLookUp:5:6] retain];
[my_lookup addObject:object];
[object release];
....

Hope this helps!

Darren Ford
+2  A: 
edoloughlin
I am probably wrong, but would you not want d=[[NSData alloc] init]; then you would need to do a [d release] at a later date. It was my understanding that alloc Allocates memory for an object, and returns it with retain count of 1. Basically its not going anywhere until you do a release (which you are responsible for).
fuzzygoat
+1  A: 

This form of class method is used to allocate and initialise an object. However you have set objOpponentTTL to nil in its declaration and never allocate it, though you do mention the required allocation line in your description. If that line were included, this function would be basically fine. Although (as ed mentions) the fact that it is called getXXX is against convention; a class method like this should be named after the object type it creates and returns.

As to the question of when to release it, that depends entirely on its lifecycle and the scope of the owning object. The short answer is: when you don't need it any more!

For example, if this object is special data associated with a team and the team belongs to a game, then you would release it in the dealloc method of your game. And the game would probably be created and released by the controller.

Others have mentioned autorelease, but that is probably not what you want here. That is useful when you have a transient object that you want to return from a method, but you will no longer have a handle to it (returning an NSString is a good example). This looks like it is part of a larger set of objects.

You really need to think about the design of your application and how the objects interact. Draw some sequence diagrams, and look at what information is needed, when, and by what objects. The example above (where a controller owns a game which owns players) is a fairly generic starting point.

The scope of an object (and where it is declared) tells you a lot. For example, if an object is a data member, you would usually allocate it in the init or awakeFromNib method, and release it in the dealloc method. If it is a factory method (such as your example), you would create it and (by convention) it is the caller's responsibility to release it. And if it is an accessor that creates a throwaway object, you would probably use autorelease.

As others have pointed out, the Apple documentation on memory management is very good. There are very clear conventions on how to safely manage memory, so it is worth grokking them and following those conventions in your own code.

gavinb