Runtime是一套C语言的API,封装了很多动态性相关的函数,平时编写的OC代码,底层都是转换成了Runtime API进行调用。
Runtime主要是用于在程序运行过程中,对OC对象做一系列的操作。
NSString类的实例,其实就是一个struct objc_object结构体的指针,所以不管是Foundation框架中的类或是自定义的类,我们创建的类的实例最终获取的都是一个结构体指针,这个结构体只有一个成员变量就是Class类型的isa指针,Class是结构体指针,指向struct objc_class。Class就是代表NSString这个类。
NSString * str = @"123";
Class c = [str class];
通过实例对象的class方法,我们可以获取到一个Class类型的变量,我们可以通过这个Class来创建相应的实例对象。
实际上,OC中的类也是一个对象,称为类对象,上述方法中通过[str class]方法获取到的就是NSString类的类对象,接着,我们就可以通过这个类对象来创建实例对象。那这个类对象,就是结构体sruct objc_class。
struct objc_class结构体定义了很多变量,通过命名不难发现,结构体里保存了指向的指针、类名、版本、实例大小、实例变量列表、方法列表、缓存、遵守的协议列表。因此可见,类对象就是一个结构体 struct objc_class,这个结构体存放的数据称为元数据,该结构体的第一个成员变量也是isa指针,这就说明了Class本身其实也是一个对象,因此我们称之为类对象,类对象在编译期产生用于创建实例对象,是单例。
类对象中的元数据存储的都是创建一个实例的相关信息,那么,类对象和类方法应该从哪里创建呢?就是从isa指针指向的结构体创建,类对象的isa指针指向的我们称之为元类(metaclass),元类中保存了创建类对象以及类方法所需要的所有信息。
c是通过一个实例对象获取的Class,实例对象可以获取到其类对象,类名作为消息的接收者时,代表的是类对象,因此类对象获取Class得到的是其本身,同时也印证了类对象是一个单例的想法。
NSLog(@"object_getClass = %@", object_getClass(p));
NSLog(@"isMetaClass = %@", class_isMetaClass(object_getClass(p))? @"yes": @"no");
NSLog(@"isMetaClass = %@", class_isMetaClass(object_getClass([Person class]))? @"yes":@"no");
NSLog(@"\nclass1=%@\nclass2=%@", object_getClass(p), object_getClass([Person class]));
一个实例对象通过class方法获取的Class就是它的isa指针指向的类对象,而类对象不是元类,类对象的isa指针指向的对象是元类。
isa
isa是一个联合体的结构
对象的isa地址 & ISA_MASK 得到类地址
类isa地址 & ISA_MASK 得到元类地址
# define ISA_MASK 0x00007ffffffffff8ULL
实例对象是一个结构体,这个结构体只有一个成员变量,指向构造它的那个类对象,这个类对象中存储了一切实例对象需要的信息,包括实例变量,实例方法等而类对象是通过元类创建的,元类中保存了类变量和类方法,这就是类映射到结构体的过程。
alloc
alloc -->
id _objc_rootAlloc(Class cls) -->
static ALWAYS_INLINE id callAlloc(Class cls, bool checkNil, bool allocWithZone=false) -->
class_createInstance -->
id class_createInstance(Class cls, size_t extraBytes)
init
id _objc_rootInit(id obj)
{
// In practice, it will be hard to rely on this function.
// Many classes do not properly chain -init calls.
return obj;
}
交由子类去重写
网友评论