Почему я не должен использовать getter для освобождения свойства в objective-c?
Мне сказал qaru.site/info/303312/..., что я не должен использовать метод getter при выпуске свойства:
@property(nonatmic, retain) Type* variable;
@synthesize variable;
// wrong
[self.variable release];
// right
[variable release];
Он не объяснил подробно почему. Они кажутся мне одинаковыми. Моя книга iOS говорит, что getter в свойстве будет выглядеть так:
- (id)variable {
return variable;
}
Значит, это не означает [self variable]
, self.variable
и variable
все равно?
Ответы
Ответ 1
Типичный геттер будет выглядеть следующим образом:
- (id)variable {
return [[variable retain] autorelease];
}
Итак, если вы используете [self.variable release]
, у вас есть дополнительные retain
и autorelease
, которые вам действительно не нужны, когда вы просто хотите освободить объект и которые вызывают освобождение объекта позже, чем необходимо (когда пул автореферата осушен).
Как правило, вы должны использовать self.variable = nil
, который имеет то преимущество, что он также устанавливает переменную в nil
(избегая сбоев из-за оборванных указателей) или [variable release]
, который является самым быстрым и может быть более уместным в dealloc
, если у вашего установщика есть пользовательская логика.
Ответ 2
Для сохраняемого свойства без специального аксессора вы можете освободить объект:
self.variable = nil;
Это влияет на установку ivar (который не может быть назван "переменная", если вы только объявили свойства), равным нулю и высвобождая предыдущее значение.
Как указывали другие, либо прямое освобождение ivar (если доступно), либо использование вышеописанного метода в порядке - то, что вы не должны делать, - это освобождение вызова от переменной, возвращаемой с геттера.
Ответ 3
Можно произвольно написать пользовательское поведение геттера, что может привести к совершенно другому поведению. Таким образом, вы не всегда можете предположить, что [variable release]
имеет те же результаты, что и [self.variable release]
.
Кроме того, вы можете писать пользовательские свойства без эксклюзивной поддержки ivar... они могут стать беспорядочными, если вы начнете выпускать объекты из ссылок, возвращаемых getters!
Могут быть дополнительные причины, о которых я не знаю...
Ответ 4
не все геттеры принимают эту форму:
- (id)variable { return variable; }
... это просто самая примитивная форма. свойства сами по себе должны предлагать больше комбинаций, которые изменяют реализацию. примитивный аксессор выше не учитывает идиомы, используемые в сочетании с управлением памятью, атомарностью или семантикой копирования. реализация также хрупка в переопределениях подклассов.
следуют некоторые действительно краткие примеры; вещи, очевидно, становятся более сложными в реальных программах, где реализации становятся значительно более сложными.
1) геттер не может вернуть переменную экземпляра. одна из нескольких возможностей:
- (NSObject *)a { return [[a copy] autorelease]; }
2) сеттер не может сохранить переменную экземпляра. одна из нескольких возможностей:
- (void)setA:(NSObject *)arg
{
...
a = [arg copy];
...
}
3) вы в конечном итоге реализуете реализацию управления памятью во всей своей программе, что затрудняет ее поддержку. семантика класса (и то, как он обрабатывает подсчет переменных переменных экземпляра) должна быть сохранена в классе и следовать соглашениям для ожидаемых результатов:
- (void)stuff:(NSString *)arg
{
const bool TheRightWay = false;
if (TheRightWay) {
NSMutableString * string = [arg mutableCopy];
[string appendString:@"2"];
self.a = string;
[string release];
// - or -
NSMutableString * string = [[arg mutableCopy] autorelase];
[string appendString:@"2"];
self.a = string;
}
else {
NSMutableString * string = [arg mutableCopy];
[string appendString:@"2"];
self.a = string;
[self.a release];
}
}
неспособность следовать этим простым правилам делает ваш код трудно поддерживать, отлаживать и мучительно расширять.
так что, тем не менее, вы хотите, чтобы ваша программа была удобной в обслуживании. вызывающий релиз непосредственно на свойство требует, чтобы вы знали много контекста внутренней работы этого класса; что, очевидно, плохо и не хватает сильных идеалов хорошего ООД.
он также ожидает, что авторы/подклассы/клиенты должны точно знать, как класс отклоняется от конвенции, что является глупым и трудоемким, когда возникают проблемы, и вы должны переучивать все внутренние детали, когда возникают проблемы (они будут в какой-то момент).
Вот некоторые тривиальные примеры того, как вызывающий релиз по результату свойства вводит проблемы. многие проблемы в реальном мире гораздо более тонкие и труднодоступные.