Оператор 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 одинаковы.