Разница между доступом к методам свойств и полям классов (Objective-C)
Предположим, что у меня есть эта часть кода:
@interface Foo : NSObject {
Bar *bar;
}
@property (retain, nonatomic) Bar *bar;
@end
При использовании этого поля/свойства существует ли разница между строками:
[self.bar doStuff];
и
[bar doStuff];
?
При выполнении присваивания метод property будет выполнять правильное сохранение, но как насчет доступа для чтения к свойству, как описано выше? Есть ли разница?
Ответы
Ответ 1
Есть большая разница.
[self.bar doStuff]
эквивалентно [[self bar] doStuff]
[bar doStuff]
эквивалентно [self->bar doStuff]
Первый использует метод доступа, последний просто обращается непосредственно к панели переменных экземпляра.
Если вы используете директиву @synthesize
по своему свойству bar
, компилятор будет генерировать для вас два метода:
- (void)setBar:(Bar*)b;
- (Bar*)bar;
Также обратите внимание, что созданный компилятором метод setter сохраняет ваш экземпляр bar
, как вы сказали в объявлении @property
.
Ответ 2
Использование accessor self.bar транслируется в вызов метода: [self bar]. Синтаксис периода предназначен только для взглядов. Доступ к переменной-члену напрямую не связан с дополнительным вызовом функции и, следовательно, немного быстрее. Это действительно имеет значение только в том случае, если вы обращаетесь к нему в цикле или в каком-то процессе, где эта разница будет складываться. (На iPhone) У сеттеров, созданных для свойств, также есть некоторые дополнительные накладные расходы для выполнения кодирования ключевых значений. Уведомление KVO отправляется, когда вы вызываете "setBar:" или говорите "self.bar =", поэтому вызов его снова и снова приведет к потоку уведомлений.
Джим прав, однако - нет функциональной разницы между неатомическим @property и прямым использованием переменной в вашем коде. Если вы действительно не заинтересованы в скорости, использование этого свойства, вероятно, лучше всего.
Ответ 3
Синтезированный (или правильно написанный) неатомический аксессуар будет функционально эквивалентен
- (Bar *)bar
{
return bar;
}
поэтому между вашими двумя примерами нет функциональной разницы.
Однако, вне -dealloc или ваших инициализаторов, постоянный доступ к свойству через его accessor является хорошей идеей.
Ответ 4
Если вы назначаете значение своему полю с помощью удобного конструктора класса Bar, ваше поле Bar станет зомби раньше, чем свойство Bar Property with Retain, потому что количество ссылок не увеличивается, назначая поля, а иногда вы запускаете в ошибку "Доступ к освобожденным объектам".