iOS中isa指针

iOS中isa指针,第1张

概述我们可以在/usr/include/objc/objc.h 和 runtime.h 中找到对 class 与 object 的定义: typedef  struct objc_class *Class; typedef  struct objc_object {     Class isa; } *id; Class 是一个 objc_class 结构类型的指针;而 id(任意对象) 是一个 ob 我们可以在/usr/include/objc/objc.h 和 runtime.h 中找到对 class 与 object 的定义:

typedef  struct objc_class *Class;
typedef  struct objc_object {
    Class isa;
} *ID;
Class 是一个 objc_class 结构类型的指针;而 ID(任意对象) 是一个 objc_object 结构类型的指针,其第一个成员是一个 objc_class 结构类型的指针。注意: 内存布局以一个 objc_class 指针为开始的所有东西都可以当做一个 object 。  那 objc_class 又是怎样一个结构体呢?
struct objc_class
{
     struct objc_class* isa;
     struct objc_class* super_class;
     const  char* name;
     long version;
     long info;
     long instance_size;
     struct objc_ivar_List* ivars;
     struct objc_method_List** methodLists;
     struct objc_cache* cache;
     struct objc_protocol_List* protocols;
};
objc_class 结构体的各成员介绍如下:
isa :是一个 objc_class 类型的指针,看到这里,想起我前面的引申解读了没? 内存布局以一个 objc_class 指针为开始的所有东东都可以当做一个 object 来对待!  这就是说 objc_class 或者说类其实也可以当做一个 objc_object 对象来对待!对象是对象,类也是对象,是不是有点混淆?别急,ObjC发明(or 重用)了一个术语来区分这两种不同的对象:类对象(class object)与实例对象(instance object)。名称混淆的问题解决,下面将使用这两个术语来区分不同的对象,而使用“对象”这一术语来泛指所有的对象。ObjC还对类对象与实例对象中的 isa 所指向的类结构作了不同的命名:类对象中的 isa 指向类结构被称作 Metaclass,Metaclass 存储类的static类成员变量与static类成员方法(+开头的方法);实例对象中的 isa 指向类结构称作 class(普通的),class 结构存储类的普通成员变量与普通成员方法(-开头的方法)。
super_class :指向该类的父类,如果该类已经是最顶层的根类(如 NSObject 或 nsproxy),那么 super_class 就为 NulL。
在继承层次中,子类,父类,根类(这些都是普通 class)以及其对应的 Metaclass 的 isa 与 super_class 之间关系如下:
规则一:类的实例对象的 isa 指向该类;该类的 isa 指向该类的 Metaclass; 规则二:类的 super_class 指向其父类,如果该类为根类则值为 NulL;
规则三:Metaclass 的 isa 指向根 Metaclass,如果该 Metaclass 是根 Metaclass 则指向自身; 规则四:Metaclass 的 super_class 指向父 Metaclass,如果该 Metaclass 是根 Metaclass 则指向该 Metaclass 对应的类;



<instance object,class,Metaclass 的 isa 与 super_class 关系图>

那么 class 与 Metaclass 有什么区别?

class 是 instance object 的类类型。当我们向实例对象发送消息(实例方法)时,我们在该实例对象的 class 结构的 methodLists 中去查找响应的函数,如果没找到匹配的响应函数则在该 class 的父类中的 methodLists 去查找(查找链为上图的中间那一排)。如下面的代码中,向str 实例对象发送 lowercaseString 消息,会在 Nsstring 类结构的 methodLists 中去查找 lowercaseString 的响应函数。

Nsstring * str;
[str lowercaseString];
Metaclass 是 class object 的类类型。当我们向类对象发送消息(类方法)时,我们在该类对象的 Metaclass 结构的 methodLists 中去查找响应的函数,如果没有找到匹配的响应函数则在该 Metaclass 的父类中的 methodLists 去查找(查找链为上图的最右边那一排)。如下面的代码中,向 Nsstring 类对象发送 stringWithString 消息,会在 Nsstring 的 Metaclass 类结构的 methodLists 中去查找 stringWithString 的响应函数。

[Nsstring stringWithString:@"str"];
好,至此我们明白了类的结构层次,让我们接着看类结构中的其他成员。
name :一个 C 字符串,指示类的名称。我们可以在运行期,通过这个名称查找到该类(通过:ID objc_getClass(const char *aClassname))或该类的 Metaclass(ID objc_getMetaClass(const char *aClassname));
version :类的版本信息,默认初始化为 0。我们可以在运行期对其进行修改(class_setVersion)或获取(class_getVersion)。
info :供运行期使用的一些位标识。有如下一些位掩码: CLS_CLASS (0x1L) 表示该类为普通 class ,其中包含实例方法和变量;
CLS_Meta (0x2L) 表示该类为 Metaclass,其中包含类方法;
CLS_INITIAliZED (0x4L) 表示该类已经被运行期初始化了,这个标识位只被 objc_addClass 所设置;
CLS_POSING (0x8L) 表示该类被 pose 成其他的类;(poseclass 在ObjC 2.0中被废弃了);
CLS_MAPPED (0x10L) 为ObjC运行期所使用 CLS_FLUSH_CACHE (0x20L) 为ObjC运行期所使用
CLS_GROW_CACHE (0x40L) 为ObjC运行期所使用 CLS_NEED_BIND (0x80L) 为ObjC运行期所使用 CLS_METHOD_ARRAY (0x100L) 该标志位指示 methodLists 是指向一个 objc_method_List 还是一个包含 objc_method_List 指针的数组;

instance_size:该类的实例变量大小(包括从父类继承下来的实例变量);


ivars :指向 objc_ivar_List 的指针,存储每个实例变量的内存地址,如果该类没有任何实例变量则为 NulL;
methodLists :与 info 的一些标志位有关,CLS_METHOD_ARRAY 标识位决定其指向的东西(是指向单个 objc_method_List还是一个 objc_method_List 指针数组),如果 info 设置了 CLS_CLASS 则 objc_method_List  存储实例方法,如果设置的是 CLS_Meta 则存储类方法;
cache :指向 objc_cache 的指针,用来缓存最近使用的方法,以提高效率;
protocols :指向 objc_protocol_List 的指针,存储该类声明要遵守的正式协议。
总结
ObjC 为每个类的定义生成两个 objc_class ,一个即普通的 class,另一个即 Metaclass。我们可以在运行期创建这两个 objc_class 数据结构,然后使用 objc_addClass 动态地创建新的类定义。 总结

以上是内存溢出为你收集整理的iOS中isa指针全部内容,希望文章能够帮你解决iOS中isa指针所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1050649.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-25
下一篇2022-05-25

发表评论

登录后才能评论

评论列表(0条)

    保存