Почему я не должен использовать метод получения, чтобы освободить свойство в target-c? - PullRequest
17 голосов
/ 31 августа 2011

Пользователь сообщил мне, что я не должен использовать метод getter при освобождении свойства:

@property(nonatmic, retain) Type* variable;
@synthesize variable;

// wrong
[self.variable release]; 

// right
[variable release]; 

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

- (id)variable {
    return variable;
}

Не значит ли это, что [self variable], self.variable и variable - это всето же самое?

Ответы [ 4 ]

13 голосов
/ 31 августа 2011

Для сохраненного свойства без пользовательского метода доступа вы можете освободить объект следующим образом:

self.variable = nil;

Это приводит к установке ивара (который нельзя назвать «переменным», если вы только объявилисвойства) до нуля и освобождая предыдущее значение.

Как уже отмечали другие, можно либо напрямую освободить ivar (если доступно), либо использовать метод, описанный выше, но вы не должны делать это, вызывая release для переменной, возвращаемой из получателя.

9 голосов
/ 31 августа 2011

При желании вы можете написать собственное поведение получателя, которое может привести к совершенно другому поведению.Таким образом, вы не можете всегда предполагать, что [variable release] имеет те же результаты, что и [self.variable release].

Кроме того, вы можете писать собственные свойства, не поддерживая их эксклюзивным ivar-кодом ... это может стать грязным, если вы начнете освобождать объекты по ссылкам, возвращаемым получателями!

Могут быть и другие причинычто я не знаю ...

4 голосов
/ 31 августа 2011

не все геттеры принимают эту форму:

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

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

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

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

- это тривиальные примеры того, как вызов release для результата свойства создает проблемы.многие проблемы в реальном мире гораздо сложнее и труднее найти.

4 голосов
/ 31 августа 2011

Типичный геттер будет выглядеть примерно так:

- (id)variable {
   return [[variable retain] autorelease];
}

Таким образом, если вы используете [self.variable release], у вас есть дополнительные retain и autorelease, которые вам на самом деле не нужны, когда вы просто хотите освободить объект, и которые вызывают освобождение объекта позже, чем необходимо (когда Автозапуск бассейн слит).

Как правило, вы либо используете self.variable = nil, преимущество которого заключается в том, что он также устанавливает переменную на nil (избегая сбоев из-за висячих указателей), либо [variable release], который является самым быстрым и может быть более подходящим в dealloc метод, если ваш установщик имеет собственную логику.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...