Objective-C对象类型怎么可能也是一个类?



Objective-C对象类型(这是一个结构体,对吧?)怎么可能也是一个类(这是一个结构体*)?

消息传递括号内的NSObject实际上是objc_class结构,它有一个指向存储类方法的元类的指针? 如果是这样,同一术语如何也是一种分配给anObject的类型?

如:NSObject * anObject = [NSObject alloc] init];

你可能想太多了;这取决于语言的定义。一种语言可以在不同的上下文中使用相同的语法元素来表示不同的语义

子表达式:

[NSObject alloc]

表示"将alloc消息发送到类型NSObject的类对象。因此,NSObject用于标识类对象。而声明:

NSObject *anObject;

表示"分配一个正确大小的变量来保存类型为NSObject *的值,并为其命名为anObject。所以这里NSObject被用来标识一个类型。

这两种用法显然密切相关,因此使用类似的语法元素,但它们具有不同的语义

呵呵


补遗

如果有帮助,声明:

NSObject *anObject = [[NSObject alloc] init];

根据定义大致相当于:

Class objectClass = objc_getClass("NSObject");
NSObject *anObject = [[objectClass alloc] init];

但是额外的语言规范/编译时间要求NSObject必须是可访问的类型,而不仅仅是字符串中的字符("NSObject")。

Objective-C 对象不一定是struct。曾几何时,他们(大部分)是,但至少从十多年前的Objective-C 2.0开始,他们就不必了。

最明显的例子:nil对象。它是一个接受任何消息并返回nil的对象。它不是一个结构。它不存在于内存中。

第二个最明显的例子:在 64 位运行时中,存储在标记指针中的任何内容都不是结构,因为表面上是指针的东西实际上并不指向任何内容。它是对象的值。堆上什么都没有。

存在各种其他示例;但是,除非您想非常广泛地将结构定义为"任何有意义的位集合",否则对象不一定是结构体。

[[NSObject alloc] init]中的NSObject是对元类的单个实例的引用NSObject,它在内存中的某处有一个表示。与对全局的任何其他引用一样,它将在二进制文件中存根,通常,实际地址将由动态链接器替换。

这是假设强链接和/或找到符号。如果你是弱链接,那么如果没有NSObject,链接器将简单地放置对nil对象的引用。

您同样可以执行[[NSClassFromString(@"NSObject") alloc] init],但效果略有不同:将尝试在运行时查找元类。所以这不是编译器通常会生成的,但是在运行时成本很小的情况下,它将允许消息传递继续,就像你静态命名类和弱链接一样。

基本上,Objective-C 中的括号语法有两种独立的语法情况:

[<expression> <selector and arguments>]
[<class name> <selector and arguments>]

虽然你可以做[NSObject alloc],但像NSObject这样的类名本身并不是Objective-C中的表达式 - 试图在代码中的其他任何地方使用NSObject就好像它是表达式一样会产生错误(这就是为什么当我们需要一个计算到类对象的指针的表达式时,我们被迫编写[NSObject class])。相反,当你写[NSObject alloc]时,它使用的是括号语法的第二种情况,其中前面的东西是类名,而不是表达式。

您可以想象当编译器编译括号语法的第二种情况时会发生什么,例如[NSObject alloc]将其转换为括号语法的第一种情况,但对于表达式,它使用指向NSObject类对象的内部指针,有点像您[objc_getClass("NSObject") alloc],只是它不需要运行时查找,并且直接在编译时链接值。

(顺便说一下,在Smalltalk中,这是Objective-C的对象系统的来源,类名是一个表达式(评估为类对象),所以在Smalltalk中发送消息的语法(除了没有括号之外几乎与Objective-C相同)不需要上面的两个单独的情况 - 第一种情况已经涵盖了第二种情况。我相信他们在制作 Objective-C 时不想制作类名表达式,因为具有相同的标识符既是类型和表达式会导致 C 解析器出现问题。

最新更新