Objective-C + релиз объектов - PullRequest
       34

Objective-C + релиз объектов

2 голосов
/ 03 декабря 2009

Я использую следующую функцию в моем приложении:

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

По сути, я возвращаю объект класса TeamTournamentLookUp.

В коде я выделяю объект: objOpponentTTL = [[TeamTournamentLookUp alloc] initWithPrimaryKey: primaryKey];

Теперь мой вопрос: куда мне отпустить объект?

Ответы [ 5 ]

4 голосов
/ 03 декабря 2009

Если вы пишете для Objective C 2, вам не нужно делать больше кода, просто создавайте сборку мусора. Если для более ранних версий, включая iPhone, вам нужно будет выпустить его на каком-то этапе.

В этом случае обычным способом является автоматическое высвобождение при создании. например,

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

Объект будет освобожден, когда вы достигнете пула автоматического выпуска. В NSApplication есть одна из них по умолчанию, которая вызывается в цикле ввода.

Подробнее об управлении памятью читайте Документы Apple по управлению памятью

1 голос
/ 03 декабря 2009

Эта форма метода класса используется для выделения и инициализации объекта. Однако вы установили objOpponentTTL в ноль в его объявлении и никогда не выделяете его, хотя в своем описании вы упоминаете обязательную строку выделения. Если бы эта строка была включена, эта функция была бы в основном нормальной. Хотя (как упоминается в издании) тот факт, что он называется getXXX, противоречит условности; метод класса, подобный этому, должен быть назван в честь типа объекта, который он создает и возвращает.

Что касается вопроса о том, когда его выпускать, то это полностью зависит от его жизненного цикла и объема объекта-владельца. Короткий ответ: когда тебе это больше не нужно!

Например, если этот объект представляет собой особые данные, связанные с командой, и команда принадлежит к игре, вы бы выпустили ее в методе dealloc вашей игры. И игра, вероятно, будет создана и выпущена контроллером.

Другие упоминали авто-релиз, но это, вероятно, не то, что вы хотите здесь. Это полезно, если у вас есть временный объект, который вы хотите вернуть из метода, но у вас больше не будет дескриптора (возвращение NSString - хороший пример). Похоже, что это часть большего набора объектов.

Вам действительно нужно подумать о дизайне вашего приложения и о том, как взаимодействуют объекты. Нарисуйте несколько диаграмм последовательности и посмотрите, какая информация необходима, когда и по каким объектам. Приведенный выше пример (где контролер владеет игрой, в которой есть игроки) является довольно общей отправной точкой.

Область объекта (и где он объявлен) говорит вам многое. Например, если объект является членом данных, вы обычно выделяете его в методе init или awakeFromNib и освобождаете его в методе dealloc. Если это фабричный метод (такой как ваш пример), вы должны его создать и (по соглашению) вызывающий должен освободить его. И если это средство доступа, которое создает одноразовый объект, вы, вероятно, используете авто-релиз.

Как уже отмечали другие, документация Apple по управлению памятью очень хорошая. Существуют очень четкие соглашения о том, как безопасно управлять памятью, поэтому стоит придерживаться их и следовать этим соглашениям в своем собственном коде.

1 голос
/ 03 декабря 2009

В дополнение к другим ответам, я хотел бы взглянуть на ваше соглашение о дизайне и наименовании, чтобы дать вашему объекту больше ясности в управлении объектами. Apple использует соглашение по всем своим API, которое ясно дает понять, когда вызывающая сторона несет ответственность за освобождение возвращаемого объекта и когда жизненный цикл объекта управляется в другом месте.

Прочитайте Руководства Apple .

Для начала название вашего метода начинается с 'get'. Для меня это означает, что он возвращает объект, который имеет свой собственный жизненный цикл, независимый от моего вызывающего метода, и я не должен его вообще освобождать!

При вызове метода, который начинается с 'make' или 'create', он сообщает мне, что возвращенный объект был создан для меня, и я несу ответственность за его освобождение, когда я закончу с ним.

Примечание : Я должен отметить, что это написано с точки зрения разработки iPhone, которая в целом невелика autorelease вещь ...

1 голос
/ 03 декабря 2009

С помощью target-c технически ваша функция должна автоматически возвращать возвращаемый объект, например.

return [autorelease objOpponentTTL];

Вызывающий объект должен сохранить возвращенный объект, например.

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

Когда вы закончите использовать объект, вы должны отпустить его, то есть.

[object release]

Я действительно не использовал Objective-C 2.0 и его сборщик мусора, поэтому я не уверен, какой должен быть синтаксис, если у вас включена сборка мусора. Однако, если вы используете стандартный Objective-C, тогда это будет хорошо для вас.

Без сборки мусора принято сохранять объект, когда вы хотите его использовать, и освобождать его, когда закончите с ним. Если вы добавите «объект» в контейнер (например, NSMutableArray), то вызываемая вами функция сохранит объект, и вы можете безопасно освободить его после добавления в коллекцию, например

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

Надеюсь, это поможет!

1 голос
/ 03 декабря 2009

Отправьте сообщение autoRelease, прежде чем вернуть его. Таким образом, ему будет отправлено сообщение о выпуске, но не только пока.

Тогда все, что вызывает ваш метод, должно будет retain возвращаемый объект.

Шаблоны обработки retain, release, autoRelease можно найти в документации Apple. Очень удобно выучить некоторые основные правила.

...