我试图围绕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
属性,但使用Objective-C,使用点运算符访问frac.numerator
。由于frac
是两个程序中的指针,为什么这些表达式不同?任何人都可以帮我澄清一下吗?
答案 0 :(得分:77)
frac
在两个程序中实际上并不相同。
C Fraction
是一个struct
,它是一个没有重载运算符的基本类型,默认情况下只能构造和销毁。如果在结构上定义函数或字段,则在C
中访问这些属性的方法是使用点(.
)运算符。当您使用struct
时,Objective-C维护此运算符。为方便起见,您可以使用箭头(->
)运算符(您提到的两个等效表达式)执行取消引用和点运算。在访问struct
时,Objective-C也会保留这一点。
然而,在您的示例中,Objective-C Fraction
可能(假设)至少是类型id
的指针,它只是一个类名和指向该类实例的指针引擎盖下。它也很可能是NSObject
或NSProxy
的子类。这些Objective-C类的特殊之处在于它们只在C
结构之上有一整层预定义操作(如果你真的想深入研究它,那么你可以看一下Objective-C Runtime Reference )。另外需要注意的是,Objective-C类总是一个指针。
最基本的操作之一是objc_msgSend
。当我们对这些类型的对象进行操作时,Objective-C编译器将点(.
)运算符或方括号语法([object method]
)解释为objc_msgSend
方法调用。有关这里实际发生的更多详细信息,请参阅负责Obj-C运行时开发的Apple工程师Bill Bumgarner的this series of posts。
箭头(->
)运算符实际上不应该用于Objective-C对象。就像我说的,Objective-C类实例是一个C结构,添加了额外的通信层,但是当您使用箭头时,该层通信基本上被绕过了。例如,如果您打开Xcode并键入[UIApplication sharedApplication]->
然后调出方法完成列表,您会看到:
在这里,您可以看到一堆普通字段,我们通常使用方括号语法(如[[UIApplication sharedApplication] delegate]
)进行访问。但是,这些特定项是C
字段,用于存储各自Objective-C属性的值。
所以,你可以大致这样想:
C对象上的点运算符
C对象上的箭头操作符(指针)
Objective-C对象(指针)上的点运算符/方括号
objc_msgSend
Objective-C对象(指针)上的箭头运算符
现在我肯定在这里过于简单了,但总结一下:在两种情况下,箭头运算符看起来基本相同,但点运算符在Objective-C中有额外/不同的含义。
答案 1 :(得分:9)
Dot-notation是一种设计选择。由于我们总是处理指向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
来访问指向对象成员的指针(如果可见)。
答案 2 :(得分:6)
在您的第一个示例中,Fraction
是一个结构。
在第二个示例中,Fraction
是Objective-C类(在iOS中可能是NSObject
的子类)。
C ++ does not allow重载operator .
。因此,如果没有其他信息,您可以推断出您所看到的点符号是集成到Objective-C中的附加语言构造,而不是C / C ++定义或重载的运算符。
实际上,点符号只是实现者选择作为属性访问速记的设计特征,完全等同于方括号getter:
myObjCVar.prop == [myObjCVar prop];
答案 3 :(得分:2)
对象上的点运算符是用于访问对象属性的特殊语法。它在幕后调用属性的getter或setter。因此,例如,[@"hello" length]
和@"hello".length
相同*。对于所有其他类型,点与C点相同,箭头始终相同。
*注意:访问者方法的名称并不总是与属性相同。如果它是声明的属性并且声明指定了一个特殊的getter或setter方法,那么将使用该方法。
答案 4 :(得分:1)
C中的点和箭头符号与Objective-C(严格超集)中的相同。我认为需要区分的根本区别在于struct和Objective-C对象之间的区别。
Objective-C中用于对象的点表示法用于Objective-C 2.0中引入的属性。但是,对于结构, - > Objective-C和C之间的点符号是相同的。