iOS - isa、superclass指针,元类superclass指向基类本身(下)

简介: 本文已同步至掘金:iOS - isa、superclass指针,元类superclass指向基类本身

三. superclass


superclass指针是相对于class对象meta-class对象来说的


定义两个Class:Person继承于NSObject,Student继承于Person。现在有个场景:通过Student的instance对象调用Person中实现的实例方法,具体的调用过程如下:


通过Student类的instance对象的isa找到对应的Student类的class对象,但没有找到相关的实现,系统会继续到superclass中找,于是会到Person类的class对象中找到具体的实现并调用


类方法的调用也是一样的


四. isa与superclass


在NSObject的头文件中,可以看到一个Class类型的isa成员变量

@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
    Class isa  OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}


在NSObject的协议里有个Class类型的成员变量superclass

@protocol NSObject
···
@property (readonly) Class superclass;
···
@end


接下来,我们看一个经典的指针逻辑分析图,分别看Objective-C面向对象语言设计、函数调用、成员变量的存储和访问是如何实现的,为什么不能多继承

image.png


image


这张图可以看到三个类:RootclassSuperclassSubClass,分别为基类父类子类,图中左到右分别为实例对象类对象元类, 举个例子:我们创建一个Person类继承自NSObject, 创建一个Student类继承自Person。则NSObjectPeronStudent分别对应RootclassSuperclassSubClass,左边的Instance对象代表实例对象,也就是我们alloc出来的实例


由图可知:


isa


  • 实例的isa指向类对象,类对象的isa指向元类对象
  • meta-class的isa都指向基类的meta-class


superclass


  • class的superclass指向父类,如果没有父类,指向nil
  • meta的superclass指向父类的meta-class,基类的meta-class的superclass指向基类的class


调用轨迹


  • instance对象:isa找到class,方法如果不存在,就通过superclass找父类
  • class对象:isa找到meta-class,方法如果不存在,就通过superclass找父类


五. isa、class、superclass关系求证


上面说到一句话


instance对象的isa值是class对象, class的isa值是meta-class对象


上图也有所体现了,再把上图标识序号,如下:


image


接下来就是证明这5条线的正确性,创建Person类继承自NSObject,代码如下:

Person *instanceObj = [[Person alloc] init];
    // 第一条线 (instance的isa值是Class对象)
    Class classCls  = object_getClass(instanceObj);
    // 第二条线 (Class对象的isa值是meta-class)
    Class metaCls = object_getClass(classCls);
    // 第三条线 (meta-class的Superclass 是 RootClass的meta-class)
    Class rootMetaCls0 = class_getSuperclass(metaCls);
    // 第四条线 (meta-class的isa值是RootClass 的meta-class)
    Class rootMetaCls1 = object_getClass(metaCls);
    //RootClass的meta-class
    Class rootMetaCls = object_getClass(rootMetaCls0);
    NSLog(@"\n instanceObj = %p \n classCls = %p \n metaCls = %p \n rootMetaCls0 = %p \n rootMetaCls1 = %p \n rootMetaCls  = %p\n", instanceObj, classCls, metaCls, rootMetaCls0, rootMetaCls1, rootMetaCls);


打印结果:

2021-05-04 16:25:08.423125+0800 ClassDemo[32740:9240333] 
 instanceObj  = 0x600002d7c0e0 
 classCls     = 0x109a21800 
 metaCls      = 0x109a217d8 
 rootMetaCls0 = 0x7fff86d48638 
 rootMetaCls1 = 0x7fff86d48638 
 rootMetaCls  = 0x7fff86d48638


注意下后边三个值是一样的,现在应该理清了,但是上面的代码中,没有isa相关的,我们仅仅是获取了对应对象的类型(Class)而已,现在想要看看对应的isa值是多少,由于isa有保护,我们可以通过kvc方式获取,也可以参考写个Class结构体.通过Bridge强转桥接C/C++再访问isa对象地址,前提是你要通过clang编译器编译出对象结构体,知道它长什么样。


我们采用kvc的方式,对代码稍作修改,查看isa值:

NSObject *object = [[NSObject alloc] init];
    Class rootCls = object_getClass(object);
    Person *instanceObj = [[Person alloc] init];
    // 第一条线 (instance的isa值是Class对象)
    Class classCls  = object_getClass(instanceObj);
    // 第二条线 (Class对象的isa值是meta-class)
    Class metaCls = object_getClass(classCls);
    // 第三条线 (meta-class的Superclass 是 RootClass的meta-class)
    Class rootMetaCls0 = class_getSuperclass(metaCls);
    // 第四条线 (meta-class的isa值是RootClass 的meta-class)
    Class rootMetaCls1 = object_getClass(metaCls);
    //RootClass的meta-class
    Class rootMetaCls = object_getClass(rootMetaCls0);
    //root-meta-class 的superclass
    Class rootMetaSuperCls = class_getSuperclass(rootMetaCls0);
    NSLog(@"\n rootCls = %p \n instanceObj = %p \n classCls = %p \n metaCls = %p \n rootMetaCls0 = %p \n rootMetaCls1 = %p \n rootMetaCls  = %p \n rootMetaSuperCls = %p \n", rootCls, instanceObj, classCls, metaCls, rootMetaCls0, rootMetaCls1, rootMetaCls, rootMetaSuperCls);
    //通过kvc方式获取isa指针
    NSLog(@"\n instanceObj-isa = %p \n classCls-isa = %p \n metaCls-isa = %p \n rootMetaCls0-isa = %p \n", [instanceObj valueForKey:@"isa"], [classCls valueForKey:@"isa"], [metaCls valueForKey:@"isa"], [rootMetaCls0 valueForKey:@"isa"]);


打印结果为:

2021-05-04 16:55:11.688427+0800 ClassDemo[49442:9299385] 
 rootCls     = 0x7fff86d48660 
 instanceObj = 0x600003e38170 
 classCls    = 0x10e5b4810 
 metaCls     = 0x10e5b47e8 
 rootMetaCls0 = 0x7fff86d48638 
 rootMetaCls1 = 0x7fff86d48638 
 rootMetaCls  = 0x7fff86d48638 
 rootMetaSuperCls = 0x7fff86d48660
2021-05-04 16:55:11.688742+0800 ClassDemo[49442:9299385] 
 instanceObj-isa = 0x10e5b4810 
 classCls-isa    = 0x10e5b47e8 
 metaCls-isa     = 0x7fff86d48638 
 rootMetaCls0-isa = 0x7fff86d48638


根据打印结果很明显:


  • instance对象的isa指向Class对象(0x10657a808, 第一条线)
  • Class对象的isa指向meta-class对象(0x10657a7e0, 第二条线)
  • meta-class的Superclass是root-meta-class (0x7fff86d48638, 第三条线)
  • meta-class的isa指向 root-meta-class (0x7fff86d48638, 第四条线)
  • root-meta-class的isa指向它自己 (0x7fff86d48638, 第五条线)
  • root-meta-class的Superclass是Rootclass (0x7fff86d48660)


六. 拓展


由于基元类的Superclass指向基类,我们会发现一个神奇的问题:如果一个类方法一直找不到,发现基类的对象方法存在,则会调用基类的对象方法,也就是子类的一个+方法,调用了基类的一个-方法。这是因为iOS的消息方法机制调用的时候没有区分对象方法和类方法,代码验证一下:


定义一个NSObject类别,里面给NSObject加一个对象方法

.h
@interface NSObject (category)
- (void)showName;
@end
.m 
@implementation NSObject (category)
- (void)showName {
    NSLog(@"NSObject (category) class = %@", NSStringFromClass([self class]));
}
@end


Person继承自NSObject,在.h声明+ (void)showName方法不实现(为了编译器不报错,也可以用runtime发消息调用)

.h
@interface Person : NSObject
+ (void)showName;
@end
.m
@implementation Person
@end


调用

[Person showName];


我们在调用Person+ (void)showName方法竟然执行了NSObject category里定义的- (void)showName方法

2021-05-04 17:09:56.436515+0800 ClassDemo[51930:9318834] NSObject (category) class = Person


这也很好的证明了基元类对象的Superclass指向基类

相关文章
|
存储 C++
04-深入了解isa指针以及内部结构
04-深入了解isa指针以及内部结构
84 0
04-深入了解isa指针以及内部结构
|
存储
03-isa指针 & superclass指针
03-isa指针 & superclass指针
66 0
|
存储 Unix 编译器
|
存储 监控 Unix
iOS-底层原理36:内存优化(一) 野指针探测
iOS-底层原理36:内存优化(一) 野指针探测
648 0
iOS-底层原理36:内存优化(一) 野指针探测
|
编译器 iOS开发
iOS逆向 03:循环选择指针(下)
iOS逆向 03:循环选择指针(下)
130 0
iOS逆向 03:循环选择指针(下)
|
存储 iOS开发 MacOS
iOS逆向 03:循环选择指针(上)
iOS逆向 03:循环选择指针(上)
83 0
iOS逆向 03:循环选择指针(上)
|
存储 C++
iOS-底层原理 09:类 & isa 经典面试题分析
iOS-底层原理 09:类 & isa 经典面试题分析
165 0
iOS-底层原理 09:类 & isa 经典面试题分析
|
存储 设计模式 编译器
iOS-底层原理 07:isa与类关联的原理
iOS-底层原理 07:isa与类关联的原理
127 0
iOS-底层原理 07:isa与类关联的原理