Objective-C: когда вызывать self.myObject или просто вызывать myObject - PullRequest
5 голосов
/ 26 августа 2009

Этот небольшой синтаксис немного запутал меня в Objective-C.

Когда я должен вызывать self.myObject против простого вызова myObject?

Это кажется избыточным, однако они не являются взаимозаменяемыми.

Кто-нибудь, пожалуйста, просветите меня?

Ответы [ 5 ]

8 голосов
/ 26 августа 2009

Если вы просто обращаетесь к ним, нет особых причин использовать self.member. Если вы выполняете присваивание, хорошо, если вы делаете больше, чем простой параметр @property (assign) - например, сохраняете, копируете и т. Д., Чтобы сэкономить на написанном вами коде. Пример:

myObject = anotherObject;
self.myObject = anotherObject;

Второй вариант гарантирует, что вы на самом деле назначаете объект так, как хотите (получаете копию, увеличиваете счетчик хранения и т. Д.). Он ничем не отличается от [self setMyObject:anotherObject].

Поскольку точечная нотация заменяется сообщением компилятором (аналогично тому, как x[5] становится *(x + 5*sizeof(x)) в работе с обычным массивом), при использовании точечной нотации над обычными сообщениями нет никаких дополнительных затрат или дополнительной эффективности.

3 голосов
/ 26 августа 2009

Хм, я не могу сказать, что я согласен с Марком или Cinder6.

Ну, я согласен с первой частью. :-) self.foo вызывает метод -foo. Обычная foo получает доступ к foo ивару.

В большинстве случаев вы всегда должны использовать свои методы. Они здесь, чтобы отвлечь вас от реального хранилища и от любого другого поведения, которое может потребоваться. Подумайте о том, что произойдет, если вы позже подкласса вашего класса. По большей части вы хотите вызывать свои собственные публичные методы в тех местах, где вы получаете доступ к их функциональности.

Исключение составляют инициализация и разрыв объекта, а также сами средства доступа к свойствам, когда вы их не синтезируете. Во время инициализации и разрыва объекта вы не хотите вызывать реализации методов подкласса, поскольку эти методы не должны иметь дело с вашим объектом в его частично настроенном состоянии.

1 голос
/ 26 августа 2009

Если вы используете Базовые данные, вам, по сути, следует всегда использовать средства доступа, поскольку некоторые свойства могут не загружаться из постоянного хранилища до тех пор, пока они не понадобятся. (В любом случае, если вы используете хранилище SQLite.)

Если вы не используете Core Data, вы можете просто использовать myObject напрямую, если вы только читаете значение. Если вы изменяете значение myObject, вам нужно использовать средства доступа, чтобы убедиться, что любые другие объекты, наблюдающие значение этого свойства, должным образом уведомлены. Другими словами:

// Not changing the value of myObject, so no accessor needed
[someMutableArray addObject:myObject];  

// Changes the value, so you need to use the accessor
self.myObject = newObject;     
[self setMyObject:newObject];  // Exactly identical to the previous line.

В целом, однако, накладных расходов очень мало; Я предпочитаю всегда использовать средства доступа, даже внутри одного и того же объекта. (Конечно, есть аргумент по поводу их использования в инициализаторах, но это отдельная проблема.)

1 голос
/ 26 августа 2009

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

Если вы используете синтезированные аксессоры, то вызов их просто добавляет (вероятно) ненужные накладные расходы. Если методы доступа имеют более сложную реализацию, то вы просто затеняете цель кода.

Наконец, некоторые новички в Objective-C используют синтаксис self.property и синтезированные средства доступа, чтобы избежать понимания управления памятью Какао. Вам действительно нужно узнать, как это работает, поэтому попытка избежать этого неэффективна.

0 голосов
/ 04 октября 2009

Там нет резаного ответа. Однако помните, что преждевременная оптимизация - это плохо. В Какао на Mac или на iPhone использование аксессоров / свойств должно быть KVO-совместимым. Соответствие KVO необходимо, чтобы базовые данные и привязки какао функционировали автоматически. В Core Data необходимо обеспечить не только KVO при изменении свойств, но и при доступе к ним.

Также лучше использовать аксессоры / свойства, когда вы хотите обеспечить поведение управления памятью свойств, то есть всегда при установке ивара для использования установщика или точечной нотации и в зависимости от того, какой шаблон управления памятью вы используете, всегда использовать аксессоры / свойства при получении ivar.

Существует несколько различных шаблонов управления памятью. Все неразрушенные объекты гарантируют, что объект, возвращенный средством доступа, будет существовать, по крайней мере, до конца текущей области автоматического выпуска. Это означает, что либо объект явно сохраняется и автоматически высвобождается в текущей области автоматического выпуска. Метод, рекомендованный Apple, делает это явно в геттере:

- (id)foo {return [[foo retain] autorelease]; }
- (void)setFoo:(id)aFoo {
  if(! [aFoo isEqual:foo]) {
     [foo release];
     foo = [aFoo retain];
  }
}

Подразумевается, что это шаблон, которому они следуют в своих синтезированных средствах доступа. Лично я предпочитаю авто-релиз в сеттере:

- (id)foo {return foo;}
- (void)setFoo:(id)aFoo {
  [foo autorelease];
  foo = [aFoo retain];
}

Это автоматически освобождает старое значение перед его заменой новым значением. Это имеет тот же эффект, что и сохранение и автоматическое освобождение в геттере, но требует, чтобы объект был добавлен в пул автоматического выпуска только один раз. Большую часть времени он имеет счетчик единиц и не выпускается автоматически, поэтому он никуда не денется, что бы ни случилось. Если свойство заменяется во время какого-то кода, который все еще удерживает его (например, в обратном вызове делегата), оно не исчезнет из-под него.

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

Последняя и лучшая причина всегда использовать аксессоры / свойства заключается в том, что для каждого свойства делается одно меньшее предположение: для этого свойства существует базовый ivar, и он имеет одно и то же имя (я полагаю, это два предположения). Возможно, в будущем вы захотите заменить ивар на производное средство доступа. Обозначение свойства все еще будет работать. Возможно, вы хотите переименовать ивар; собственность все еще будет работать. К счастью, на рефакторинг в Xcode обычно можно положиться, но зачем вообще беспокоиться?

Смысл объектно-ориентированного программирования - использовать интерфейсы, определенные в классе. Нет веской причины (хотя есть много предубежденных и рационализированных) для класса игнорировать свой собственный интерфейс. Каждый метод, за исключением самих методов доступа, должен в общем случае трактовать объект как священный, а его внутреннее состояние - как частное. Напишите каждый метод, как если бы он находился в категории или в подклассе, и рассматривайте ivars как частное состояние, если конкретный дизайн не требует, чтобы вы поступили иначе. Существует множество веских причин для прямого доступа к иварам, но они определяются в каждом конкретном случае.

...