Подтвердить что ты не робот

Почему я не должен использовать 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 все равно?

4b9b3361

Ответ 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];
    }
}

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

так что, тем не менее, вы хотите, чтобы ваша программа была удобной в обслуживании. вызывающий релиз непосредственно на свойство требует, чтобы вы знали много контекста внутренней работы этого класса; что, очевидно, плохо и не хватает сильных идеалов хорошего ООД.

он также ожидает, что авторы/подклассы/клиенты должны точно знать, как класс отклоняется от конвенции, что является глупым и трудоемким, когда возникают проблемы, и вы должны переучивать все внутренние детали, когда возникают проблемы (они будут в какой-то момент).

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