一、类的数据结构
Class(指针)
typedef struct objc_class *Class;
/*
这是由编译器为每个类产生的数据结构,这个结构定义了一个类.这个结构是通过编译器在执行时产生,在运行时发送消息时使用.因此,一些成员改变了类型.编译器产生"char* const"类型的字符串指针替代了下面的成员变量"super_class"
*/
struct objc_class {
struct objc_class* class_pointer; /* 指向元类的指针. */
struct objc_class* super_class; /* 指向父类的指针. 对于NSObject来说是NULL.*/
const char* name; /* 类的名称. */
long version; /* 未知. */
unsigned long info; /* 比特蒙板. 参考下面类的蒙板定义. */
long instance_size; /* 类的字节数.包含类的定义和所有父类的定义 */
#ifdef _WIN64
long pad;
#endif
struct objc_ivar_list* ivars; /* 指向类中定义的实例变量的列表结构. NULL代表没有实例变量.不包括父类的变量. */
struct objc_method_list* methods; /* 链接类中定义的实例方法. */
struct sarray * dtable; /* 指向实例方法分配表. */
struct objc_class* subclass_list; /* 父类列表 */
struct objc_class* sibling_class;
struct objc_protocol_list *protocols; /* 要实现的原型列表 */
void* gc_object_type;
};
Method(指针)
typedef struct objc_method *Method;
/* 编译器依据类中定义的方法为该类产生一个或更多这种这种结构.
一个类的实现可以分散在一个文件中不同部分,同时类别可以分散在不同的模块中.为了处理这个问题,使用一个单独的方法链表 */
struct objc_method
{
SEL method_name; /* 这个变量就是方法的名称.编译器使用在这里使用一个`char*`,当一个方法被注册,名称在运行时被使用真正的SEL替代 */
const char* method_types; /* 描述方法的参数列表. 在运行时注册选择器时使用.那时候方法名就会包含方法的参数列表.*/
IMP method_imp; /* 方法执行时候的地址. */
};
Ivar(指针)
typedef struct objc_ivar *Ivar;
/* 编译器依据类中定义的实例变量为该类产生一个或更多这种这种结构 */
struct objc_ivar
{
const char* ivar_name; /* 类中定义的变量名. */
const char* ivar_type; /* 描述变量的类型.调试时非常有用. */
int ivar_offset; /* 实例结构的基地址偏移字节 */
};
Category(指针)
typedef struct objc_category *Category;
/* 编译器为每个类别产生一个这样的结构.一个类可以具有多个类别同时既包括实例方法,也可以包括类方法*/
struct objc_category
{
const char* category_name; /* 类别名.定义在类别后面的括号内*/
const char* class_name; /* 类名 */
struct objc_method_list *instance_methods; /* 链接类中定义的实例方法. NULL表示没有实例方法. */
struct objc_method_list *class_methods; /* 链接类中定义的类方法. NULL表示没有类方法. */
struct objc_protocol_list *protocols; /* 遵循的协议表 */
};
objc_property_t
typedef struct objc_property *objc_property_t;
IMP
id (*IMP)(id, SEL, ...)
SEL
typedef struct objc_selector *SEL;
struct objc_selector
{
void *sel_id;
const char *sel_types;
};
objc_method_list
struct objc_method_list
{
struct objc_method_list* method_next; /* 这个变量用来链接另一个单独的方法链表 */
int method_count; /* 结构中定义的方法数量 */
struct objc_method method_list[1]; /* 可变长度的结构 */
};
objc_cache
struct objc_cache
{
unsigned int mask;
unsigned int occupied;
Method buckets[1];
};
objc_protocol_list
struct objc_protocol_list
{
struct objc_protocol_list *next;
size_t count;
struct objc_protocol *list[1];
};
二、实例的数据结构
id
typedef struct objc_object *id;
objc_object
struct objc_object
{
// 类的指针是对象相关的类.如果是一个类对象, 这个指针指向元类.
Class isa;
};
objc_super
struct objc_super
{
id self; /* 消息的接受者 */
Class super_class; /* 接受者的父类 */
};
三、底层-Class详解(iOS)
• iOS的开发语言objective-c,它的真实面目是它不是真正的面向对象语言,而抽象理解为此而已。其实它就是C+,有个公式可以很好地诠释那就是OC = C + Runtime;
• 接下来我们就好好讲讲在Runtime下的objc-class。
3.1Class定义
3.1.1 小小说明一下objc-api.h里的OBJC_ISA_AVAILABILITY:
• /*介绍一下attribute((deprecated))的作用,__attribute是给函数、变量、类做属性说明的关键字,deprecated是弃用原先的进行兼容
• 若是OBJC2,原先的类,编译器发出警告*/
#if !defined(OBJC_ISA_AVAILABILITY)
# if __OBJC2__
# define OBJC_ISA_AVAILABILITY __attribute__((deprecated))
# else
# define OBJC_ISA_AVAILABILITY /* still available */
# endif
#endif
typedef struct objc_method *Method;
typedef struct objc_ivar *Ivar;
typedef struct objc_category *Category;
typedef struct objc_property *objc_property_t;
3.1.2 接下来就是runtime.h里的Class的定义:
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;//每个Class都有一个isa指针
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;//父类
const char *name OBJC2_UNAVAILABLE;//类名
long version OBJC2_UNAVAILABLE;//类版本
long info OBJC2_UNAVAILABLE;//!*!供运行期使用的一些位标识。如:CLS_CLASS (0x1L)表示该类为普通class; CLS_META(0x2L)表示该类为metaclass等(runtime.h中有详细列出)
long instance_size OBJC2_UNAVAILABLE;//实例大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;//存储每个实例变量的内存地址
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;//!*!根据info的信息确定是类还是实例,运行什么函数方法等
struct objc_cache *cache OBJC2_UNAVAILABLE;//缓存
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;//协议
#endif
} OBJC2_UNAVAILABLE;
四、class初始化
• Runtime的行为之一就是initialize。在程序运行过程中,它会在你程序中每个类调用一次initialize。这个调用的时间发生在你的类接收到消息之前,但是在它的超类接收到initialize之后。
//在苹果的官方Runtime中有个objc-initialize.m文件,进行解读
typedef struct _objc_initializing_classes {
int classesAllocated;//类是否分配存在
Class *metaclasses;//类的父类,如果没有父类那就是自身
}
_objc_initializing_classes;//初始化一个对象_objc_initializing_classes
//将所有的类存储在静态链表中,以待接下来的接收和发送消息
static _objc_initializing_classes *_fetchInitializingClassList(BOOL create)
{
_objc_pthread_data *data;
//list为类链表
_objc_initializing_classes *list;
Class *classes;
data = _objc_fetch_pthread_data(create);
if (data == nil) return nil;
//链表增加类节点
list = data->initializingClasses;
if (list == nil) {
if (!create) {
return nil;
} else {
list = (_objc_initializing_classes *)
_calloc_internal(1, sizeof(_objc_initializing_classes));
data->initializingClasses = list;
}}//将创建的classes接在metaclasses后
classes = list->metaclasses;
if (classes == nil) {
// If _objc_initializing_classes exists, allocate metaclass array,
// even if create == NO.
// Allow 4 simultaneous class inits on this thread before realloc.
list->classesAllocated = 4;
classes = (Class *)
_calloc_internal(list->classesAllocated, sizeof(Class));
list->metaclasses = classes;
}return list;
}
五、runtime下Class的各项操作(重要几个)
5.1 add*(增加)
5.1.1 static IMP addMethod(Class cls, SEL name, IMP imp, const char *types, BOOL replace);//增加方法
5.1.2 BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);//增加类方法
5.1.3 BOOL class_addIvar(Class cls, const char *name, size_t size,uint8_t alignment, const char *type);//增加实例变量
5.1.4 static BOOL _class_addProperty(Class cls, const char *name,const objc_property_attribute_t *attrs, unsigned int count,BOOL replace);//增加属性
5.2 replace*(修改)
5.2.1 IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types); //修改方法
5.2.2 void class_replaceProperty(Class cls, const char *name,const objc_property_attribute_t *attrs, unsigned int n);//修改属性
5.3 get*(获取)
5.3.1 static Class getClass(const char *name);//获取类
5.3.2 static ivar_t *getIvar(Class cls, const char *name);//获取类变量(static相当于“+“)
5.3.3 Method class_getInstanceMethod(Class cls, SEL sel);//获取实例方法
5.3.4 static Method _class_getMethod(Class cls, SEL sel);;//获取类方法
5.3.5 static Protocol *getProtocol(const char *name);//增加协议
5.4 set*(设置)
5.4.1 objc_class::setInitialized();//set的initialized初始化
5.4.2 static Class setSuperclass(Class cls, Class newSuper);//设置父类
5.5 其他还有类似于 void *objc_destructInstance(id obj);//摧毁实例对象等等
六、Class的重要函数
6.1 get*(获取)
6.1.1 object_getClass(id obj);
6.1.2 IMP object_getMethodImplementation(id obj, SEL name);//获得实例方法实现
6.1.3 Ivar object_getInstanceVariable(id obj, const char *name, void **value)//获取实例属性
6.2 set*(设置)
6.2.1 Class object_setClass(id obj, Class cls);
6.2.2 Ivar object_setInstanceVariable(id obj, const char *name, void *value);//设置实例属性
6.2.3 void object_setIvar(id obj, Ivar ivar, id value);//设置实例变量
6.3 其他
6.3.1 static void _class_resolveClassMethod(Class cls, SEL sel, id inst);//动态添加类方法,不必在乎方法是否存在
6.3.2 static void _class_resolveInstanceMethod(Class cls, SEL sel, id inst);//动态添加实现方法,不必在乎方法是否存在
6.3.3 unsigned _class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone,id *results, unsigned num_requested);//创建实例存储空间
6.4 消息转发
6.4.1 void instrumentObjcMessageSends(BOOL flag);//flag传入YES,运行时发送的所有消息都会打印到/tmp/msgSend-xxxx文件里了。
站在巨人的肩膀上才有这些总结
菜鸟走向大牛,大家共同前进,如果觉得不错,请给个赞/关注。
一起交流学习,有问题随时欢迎联系,邮箱:383708669@qq.com