Разница между доступом к методам свойств и полям классов (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, потому что количество ссылок не увеличивается, назначая поля, а иногда вы запускаете в ошибку "Доступ к освобожденным объектам".