Оператор Dot ( "." ) И стрелка ( "->" ) используют в C vs. Objective-C

Я пытаюсь склонить голову к некоторым различиям в использовании и синтаксисе в C vs. Objective-C. В частности, я хочу знать, как (и почему) использование отличается для оператора точки и оператора стрелки в C vs. Objective-C. Вот простой пример.

C Код:

// declare a pointer to a Fraction
struct Fraction *frac;

...

// reference an 'instance' variable
int n = (*frac).numerator;     // these two expressions
int n = frac->numerator;       // are equivalent

Objective-C Код:

// declare a pointer to a Fraction
Fraction *frac = [[Fraction alloc] init];

...

// reference an instance variable
int n = frac.numerator;        // why isn't this (*frac).numerator or frac->numerator??

Итак, видя, как frac одинаково в обеих программах (т.е. это указатель на объект или структуру фракции), почему они используют другой синтаксис при доступе к свойствам? В частности, в C свойство numerator получает доступ с помощью frac->numerator, но с Objective-C он обращается к оператору точек с помощью frac.numerator. Поскольку frac является указателем в обеих программах, почему эти выражения отличаются? Может кто-нибудь помочь прояснить это для меня?

Ответ 1

frac на самом деле не то же самое в обеих программах.

A C Fraction - это struct, который является базовым типом без перегруженных операторов и по-настоящему может быть сконструирован и разрушен по умолчанию. Если вы определяете функции или поля в структуре, способ доступа к этим свойствам в C выполняется с помощью оператора точки (.). Objective-C поддерживает этот оператор, когда вы используете struct s. Для удобства вы можете выполнить операцию разыменования и точки с помощью оператора стрелки (->) (упомянутые два эквивалентных выражения). Objective-C также сохраняет это при доступе к struct s.

An Objective-C Fraction в вашем примере, однако, вероятно, (можно было бы предположить) указатель хотя бы типа id, который просто является именем класса и указателем на экземпляр этого класса под капотом. Он также, скорее всего, будет подклассом NSObject или NSProxy. Эти классы Objective-C отличаются тем, что у них есть целый уровень предопределенных операций поверх структуры C (если вы действительно хотите в нее вникнуть, тогда вы можете взглянуть на Objective-C Справочник по времени выполнения). Также важно отметить, что класс Objective-C всегда является указателем.

Одна из основных операций - objc_msgSend. Когда мы работаем с этими типами объектов, компилятор Objective-C интерпретирует оператор точки (.) или синтаксис квадратной скобки ([object method]) в качестве вызова метода objc_msgSend. Более подробную информацию о том, что на самом деле происходит здесь, см. эту серию сообщений Билла Бумгарнера, инженера Apple, который курирует разработку Obj-C во время выполнения.

Оператор стрелки (->) на самом деле не должен использоваться для объектов Objective-C. Как я уже сказал, экземпляры класса Objective-C представляют собой C-структуру с добавленным дополнительным уровнем связи, но этот уровень связи существенно обходит, когда вы используете стрелку. Например, если вы откроете Xcode и введите [UIApplication sharedApplication]->, а затем откройте список завершения метода, вы увидите следующее:

A list of internal ivars on an Obj-C object when using the arrow operator

Здесь вы можете увидеть кучу нормальных полей, к которым мы обычно обращаемся с синтаксисом с квадратной скобкой (например, [[UIApplication sharedApplication] delegate]). Однако эти конкретные элементы представляют собой поля C, в которых хранятся значения их соответствующих свойств Objective-C.

Итак, вы можете примерно подумать об этом так:

Оператор Dot на объекте C

  • (во время выполнения) Возвращаемое значение поля

Оператор стрелки на объекте C (указатель)

  • Указатель разыменования
  • Возвращаемое значение поля

Оператор точки/квадратные скобки на объекте Objective-C (указатель)

  • (во время компиляции) Заменить на вызов objc_msgSend
  • (во время выполнения) Посмотрите определение класса Obj-C, исключите исключение, если что-то пошло не так.
  • Указатель разыменования
  • Возвращаемое значение поля

Оператор стрелки на объекте Objective-C (указатель)

  • (во время выполнения) Указатель разницы
  • Возвращаемое значение поля

Теперь я определенно упрощаю здесь, но резюмирую: операторы стрелок, по-видимому, делают в обоих случаях одно и то же, но оператор-точка имеет дополнительное/различное значение в Objective-C.

Ответ 2

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

Точечная нотация имеет значение, хотя - это не прямой доступ, а сообщение.

То есть:

obj.property = val;
// is the same as:
[obj setProperty:val];
// and not:
obj->property = val;


val = obj.property;
// is the same as:
val = [obj property];
// and not:
val = obj->property;

Вы все равно можете написать obj->ivar для доступа к указателю на члены объекта (если видимо).

Ответ 3

В вашем первом примере Fraction является структурой. Во втором примере Fraction - это класс Objective-C (а в iOS, вероятно, будет подкласс NSObject).

С++ не позволяет перегружать operator .. Поэтому без дополнительной информации вы можете сделать вывод, что точечное обозначение, которое вы видите, является дополнительной конструкцией языка, интегрированной в Objective-C, а не с определенным или перегруженным оператором C/С++.

Как это бывает, нотация точек - это просто конструктивная особенность, которую разработчики выбрали как стенографию доступа к свойствам, полностью эквивалентную элементу с квадратной скобкой:

myObjCVar.prop == [myObjCVar prop];

Ответ 4

Точечный оператор на объектах является специальным синтаксисом для доступа к свойствам объектов. Он вызывает свойство getter или setter за кулисами. Так, например, [@"hello" length] и @"hello".length эквивалентны *. Для всех других типов точка совпадает с точкой C, а стрелка всегда одна и та же.

* Примечание. Метод доступа не всегда будет называться так же, как и свойство. Если это объявленное свойство и объявление обозначают специальный метод getter или setter, тот будет использоваться вместо этого.

Ответ 5

Точечная и стрелочная нотации одинаково одинаковы для C, как в Objective-C (строгий суперсет). Я думаю, что основное отличие, которое нужно различить, - это различие между объектом struct и Objective-C.

Точечная нотация, используемая для объектов в Objective-C, используется для свойств, введенных в Objective-C 2.0. Тем не менее, с structs, → и точечная нотация между Objective-C и C одинаковы.