我的理解是 Objective-C 中的对象和类只是结构。
分别只是:
struct objc_class *
和
struct objc_object *
问题#1:
objc_msgSend(id self, SEL _cmd);
据我所知, id
的类型为struct objc_object *
但是当我们调用类方法时,类是struct objc_class *
,
我希望它会引起问题或者喊出某种警告,例如“嘿,这里的错误类型,我的朋友”。
但没有。
这只是为了满足我的好奇心,因为即使没有完全理解这一点,它似乎也没有给我带来任何麻烦(到目前为止)。但我想深入挖掘并学习基本原理/“特点”。
问题#2:
由于根据我的经验(与 问题#1 相关)没有警告,因此我不太确定他们可能< / em>可以互换使用。
struct objc_class *
和struct objc_object *
真的可以互换使用吗?
如果是:
您能否向我展示一个场景和样本,以及/如何/为何需要互换使用这些场景?
利益(如果有),缺点(如果有)和“陷阱”(需要注意的事项)出去;如果有的话)这样做?
答案 0 :(得分:8)
我的理解是Objective-C中的对象和类只是结构。
这不是真的,特别是因为ObjC2,并且绝对不是一个好的思考方式。有问题的“结构”定义了一个字段(isa
)。而已。它只是名义上的“结构”。
请注意,ARC对象和结构在编译器中的处理方式不同。对象指针将获得结构指针不会的特殊处理(包括nil-initialization)。编译器还将->
不同地应用于对象而不是结构。结构指针必须具有在->
之后给出名称的字段。 objc_object
只有一个字段(isa
)。由于可以在运行时定义和重新定义类层次结构,因此编译器无法像编译结构那样在编译时为对象评估->
。
我提出这一点是因为在C ++中,对象和结构只是同一个东西的略有不同的版本,你可以轻松地在它们之间进行交换。你不能在ObjC中安全地做到这一点。它们几乎不相似。
但是当我们调用类方法,类
struct objc_class *
的类时,我希望它会导致问题......
This is because classes are objects.对象未定义为objc_object
类型。它们是根据isa
字段(它曾经是指针,但现在可能是指针,or it might not)来定义的。这是假设typedef是重要的问题的一部分。事实并非如此。重要的是它是否像一个物体。 Objective-C是一种主要是鸭式的语言。如果它像一个对象,它就是一个对象。
NSProxy
也生活在这个奇怪的近乎对象的世界里。如果你注意它的定义,它不会从任何东西继承,但它确实声明了isa
字段作为它的第一个ivar。这是让它像对象一样行动的关键部分。
结构objc_class *和struct objc_object *真的可以互换使用吗?
没有。您通常可以将类传递给任何想要对象的东西(因为类是对象),但是您不能将对象传递给想要类的东西。
答案 1 :(得分:5)
我在runtime.h文件中找到它。
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
objc_class和objc_object都有isa变量,objc_object中的isa指向描述实例并存储实例方法列表的Class。 objc_class中的Isa也指向Class,但它是描述类并存储类方法列表的元类。
The link对您有用。
我已经模拟了病情。
struct A {
int a ;
} ;
typedef struct A *PA ;
struct B {
int a ;
int b ;
} ;
void dosomething(PA pa)
{
printf("%d", (*pa).a) ;
}
+ (void)hei
{
struct B b ;
b.a = 10 ;
b.b = 20 ;
// without forced cast, i will get a warning but work well
dosomething((PA)&b) ;
}
您可以使用struct B *
代替struct A *
,因为编译器和链接器会将int a
放在相同的相对地址中。
为什么编译器在调用将struct objc_class *
传递给objc_msgSend(id self, SEL _cmd);
的类方法时不会抱怨,在我看来编译器会考虑它。