OC类的探索-isa

299 阅读3分钟

类的获取

在日常开发当中我们一般通过如下方式获取对象所属的类;

Class class1 = [FMUserInfo alloc].class;

除此之外还有如下等方式来获取某个类:

Class class2 = [FMUserInfo alloc].class;
Class class3 = object_getClass([FMUserInfo alloc]);

通过运行可以看到,不管通过什么方式获取,其内存地址始终为一个 image.png

类的结构

我们知道类Class的类型是objc_class类型

typedef struct objc_class *Class;

通过查看源码(我这里是838.1版本)可以查看其定义部分:

//类对象
struct objc_class : objc_object {
    // Class ISA; // 8
    Class superclass;// 8
    cache_t cache;   // 16         // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags //
    ......
}

类其实是一个继承自的objc_object结构体,而我们知道对象的本质其实也是objc_object,因此类其实也是一个对象,即类对象。观objc_class定义,其内部包含isa、superclass、cache、bits等结构。

  • isa 类的isa指针
  • superclass 继承的类
  • cache 缓存
  • bits 类的内部数据

类的isa

我们知道对象的isa指向的是类,而前文中也说,类其实也是一个对象,那么类对象的isa指向的又是谁呢?

image.png 我们先通过实例对象p的isa获取到了类对象FMUserInfo,那么我们用同样的方式查看下类的isa指向的是谁。

image.png

通过实际测试发现,类的isa同样指向的是FMUserInfo,但是这两个FMUserInfo的地址明显不是同一个,我们通过p/x [FMUserInfo class]打印下FMUserInfo类对象的地址。显然类的地址为前者,后者即为类的元类。

image.png

元类的isa

我们继续打印下元类的isa指向的是谁呢?

image.png

通过打印发现元类的isa指向的是NSObject,那么此处的NSObject是否系统定义的NSObject为同一个呢?

image.png 明显这两者也不是同一个,这里打印出来的NSObject根元类,我们再次用相同的方式打印,可以发现根元类的isa指向本身。

image.png 所以其isa的指向图如下图所示: image.png

类与元类

上文中我们探讨了对象、类与元类的isa的指向关系,那么类与元类之间的继承关系又是如何?

类的继承链

我们准备一个子类FMManagerInfo,其继承自FMUserInfo,通过runtime提供的class_getSuperclass方法来获取该类继承自哪个类,

 FMManagerInfo *t = [FMManagerInfo alloc];
 FMUserInfo  *p = [FMUserInfo alloc];
 NSLog(@"%@-%@",t,p);
    
 NSLog(@"%@",class_getSuperclass(FMManagerInfo.class));
 NSLog(@"%@",class_getSuperclass(FMUserInfo.class));
 NSLog(@"%@",class_getSuperclass(NSObject.class));

其运行结果如下:

image.png 其继承关系如下:

graph LR
A[子类] --继承自--> B[父类] --继承自--> C[NSObject] --继承自--> D[null]

元类链

那么元类的继承关系呢?objc_getMetaClass方法可以用来获取某个类的元类,所以与class_getSuperclass相结合,我们用如下代码来测试下:

NSLog(@"%@--元类为:%@ 地址为%p,其父类为%@,元类的父类为%@ 地址为:%p",FMManagerInfo.class,objc_getMetaClass([NSStringFromClass(FMManagerInfo.class) cStringUsingEncoding:NSASCIIStringEncoding]),objc_getMetaClass([NSStringFromClass(FMManagerInfo.class) cStringUsingEncoding:NSASCIIStringEncoding]),class_getSuperclass(FMManagerInfo.class),class_getSuperclass(objc_getMetaClass([NSStringFromClass(FMManagerInfo.class) cStringUsingEncoding:NSASCIIStringEncoding])),class_getSuperclass(objc_getMetaClass([NSStringFromClass(FMManagerInfo.class) cStringUsingEncoding:NSASCIIStringEncoding])));
    
NSLog(@"%@--元类为:%@ 地址为%p,其父类为%@,元类的父类为%@ 地址为:%p",FMUserInfo.class,objc_getMetaClass([NSStringFromClass(FMUserInfo.class) cStringUsingEncoding:NSASCIIStringEncoding]),objc_getMetaClass([NSStringFromClass(FMUserInfo.class) cStringUsingEncoding:NSASCIIStringEncoding]),class_getSuperclass(FMUserInfo.class),class_getSuperclass(objc_getMetaClass([NSStringFromClass(FMUserInfo.class) cStringUsingEncoding:NSASCIIStringEncoding])),class_getSuperclass(objc_getMetaClass([NSStringFromClass(FMUserInfo.class) cStringUsingEncoding:NSASCIIStringEncoding])));
    
NSLog(@"%@--元类为:%@ 地址为%p,其父类为%@,元类的父类为%@ 地址为:%p",NSObject.class,objc_getMetaClass([NSStringFromClass(NSObject.class) cStringUsingEncoding:NSASCIIStringEncoding]),objc_getMetaClass([NSStringFromClass(NSObject.class) cStringUsingEncoding:NSASCIIStringEncoding]),class_getSuperclass(NSObject.class),class_getSuperclass(objc_getMetaClass([NSStringFromClass(NSObject.class) cStringUsingEncoding:NSASCIIStringEncoding])),class_getSuperclass(objc_getMetaClass([NSStringFromClass(NSObject.class) cStringUsingEncoding:NSASCIIStringEncoding])));

image.png

image.png 所以其整个流程图如下

image.png

元类与父类

那么对于某个自定义类如FMUserInfo,父类与元类的关系如何?

// FMUserInfo  -- 元类的父类就是父类的元类
Class FMetaClass = class_getSuperclass(objc_getMetaClass([NSStringFromClass(FMUserInfo.class) cStringUsingEncoding:NSASCIIStringEncoding]));
Class FsuperClass = objc_getMetaClass([NSStringFromClass(class_getSuperclass(FMUserInfo.class)) cStringUsingEncoding:NSASCIIStringEncoding]);
NSLog(@"元类的父类%@ - %p",FMetaClass,FMetaClass);
NSLog(@"父类的元类%@ - %p",FsuperClass,FsuperClass);

image.png 通过打印发现元类的父类与父类的元类其实是同一个,所以也就得出了经典的继承关系链;

image.png