点(“。”)运算符和箭头(“ – >”)运算符在C和Objective-C中使用

我试图围绕C和Objective-C中的一些使用和语法差异来解决问题。 特别是,我想知道在C和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是如何相同的(即它是一个指向Fraction对象或结构的指针),为什么在访问属性时他们使用不同的语法? 特别是在C语言中, numerator属性是用frac->numerator numerator来访问的,而在Objective-C中,它是用点运算符和frac.numerator来访问的。 由于frac是两个程序的指针,为什么这些expression不同呢? 任何人都可以帮我澄清这一点?

在两个scheme中frac实际上是不一样的。

交换Fraction是一个struct ,它是一个没有重载操作符的基types,只能真正的被构造和破坏。 如果你在结构上定义了函数或者字段,那么在C访问这些属性的方法是使用点( . )运算符。 当你使用struct时,Objective-C维护这个运算符。 为方便起见,您可以使用箭头( -> )运算符(您提到的两个等效expression式)执行解引用和点运算。 Objective-C在访问struct时也保留了这一点。

然而,在你的例子中的一个Objective-C Fraction可能(至less会假设)一个至less是typesid的指针,它只是一个类名和指向该类下的类的实例的指针。 它也很可能是NSObjectNSProxy一个子类。 这些Objective-C类是特别的,因为它们在C结构之上有一整层预定义的操作(如果你真的想深入研究它,那么你可以看一下Objective-C运行时参考 )。 同样重要的是要注意,一个Objective-C类总是一个指针

其中最基本的操作是objc_msgSend 。 当我们对这些types的对象进行操作时,Objective-C编译器将一个点( . )运算符或方括号语法( [object method] )解释为一个objc_msgSend方法调用。 有关这里实际发生情况的更多详细信息,请参阅负责监督Obj-C运行时开发的苹果工程师Bill Bumgarner撰写的这一系列文章 。

箭头( -> )运算符不是真的应该用在Objective-C对象上。 就像我所说的,Objective-C类实例是一个C结构,增加了额外的通信层,但是当使用箭头时,这个通信层基本上被绕过了。 例如,如果打开Xcode并键入[UIApplication sharedApplication]-> ,然后调出方法完成列表,您将看到:

使用箭头运算符时Obj-C对象上的内部ivars列表

在这里你可以看到一些普通的字段,我们通常用方括号语法来访问(比如[[UIApplication sharedApplication] delegate] )。 但是,这些特定的项目是存储其各自Objective-C属性值的C字段。

所以,大致可以这样想:

在C对象上的点运算符

  1. (在运行时)字段的返回值

C对象上的箭头运算符(指针)

  1. 取消引用指针
  2. 返回该字段的值

点操作符/方括号在Objective-C对象(指针)

  1. (在编译时)replace为调用objc_msgSend
  2. (在运行时)查找Obj-C类的定义,如果出现错误则抛出exception
  3. 取消引用指针
  4. 返回该字段的值

一个Objective-C对象上的箭头运算符(指针)

  1. (在运行时)解引用指针
  2. 返回该字段的值

现在我在这里肯定是简单化了,但总结一下:在这两种情况下,箭头运算符看起来基本上是一样的,但点运算符在Objective-C中有一个额外/不同的含义。

点符号是一个deviseselect。 因为我们总是处理objc实例的指针,所以我猜devise师需要一些熟悉的东西,这也不会破坏现有的程序。 它是在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来访问一个指向对象成员的指针(如果可见的话)。

在你的第一个例子中, Fraction是一个结构。 在第二个例子中, Fraction是一个Objective-C类(在iOS中可能是NSObject一个子类)。

C ++ 不允许 operator .重载operator . 。 因此,如果没有附加信息,则可以推断出您所看到的点符号是集成到Objective-C中的另一种语言结构,而不是C / C ++定义的或重载的运算符。

实际上,点符号仅仅是实现者select的属性访问的简写的devise特征,完全等价于方括号的getter:

 myObjCVar.prop == [myObjCVar prop]; 

对象上的点运算符是访问对象属性的特殊语法。 它在幕后调用属性的getter或setter。 所以,例如, [@"hello" length]@"hello".length是相等的*。 对于所有其他types,点与C点相同,箭头始终相同。

*注意:访问器方法不总是与属性名称相同。 如果它是一个声明的属性,并且该声明指定了一个特殊的getter或setter方法,则将使用该方法。

C中的点和箭号表示法与Objective-C(严格超集)中的相同。 我认为需要区分的基本差异是结构和Objective-C对象之间的区别。

Objective-C中用于对象的点符号用于Objective-C 2.0中引入的属性。 但是,对于结构体,Objective-C和C之间的 – >和点符号是相同的。