美文网首页
isa 和 superclass

isa 和 superclass

作者: 张_何 | 来源:发表于2020-02-15 18:31 被阅读0次
    • 实例对象的 isa 指向类对象,类对象的 isa 指向元类对象,元类的isa 指向基类的元类对象,基类的元类对象的 isa 指向自己

    • 类对象的 superclass指向父类的类对象,如果没有父类,则 superclass 指向 nil.

    • 元类对象的 superclass 指向父类的元类对象,如果没有父类(证明该类是基类),则superclass 指向类对象.

    • 实例对象调用对象方法的轨迹: 对象的 isa 找到类对象,如果方法不存在,则通过类对象中的 superclass 找父类...

    • 类对象调用类方法的的轨迹:类对象的 isa 找到元类对象,如果方法不存在,就通过元类对象中的 superclass 找父类...


      isa 和 superclass.png
    • 类可以调实例方法吗?

    @implementation NSObject(Test)
    -(void)test{
        NSLog(@"%p",self); //输出 0x1000011b8
    }
    @end
    @interface Person : NSObject
    +(void)test;
    @end
    @implementation Person
    @end
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            NSLog(@"[Person class] - %p",[Person class]); //输出 0x1000011b8
            [Person test];
        }
        return 0;
    }
    

    通过上面代码我们看到类是可以调用实例方法的.这是为什么呢?
    这要从 OC 方法调用的底层说起,我们知道oc 的方法调用最后都是通过转成 objc_mesageSend()函数调用的,这个方法接收两个参数,一个是对象(实例对象或类对象),另外一个是 Selector.问题就出在这个 Selector 上,这个 selector 并没有区分是实例方法还是类方法.方法调用就根据传入对象的 isa 指针去查找方法.当我们传入的对象是实例对象时,会根据 实例对象的isa 指针找到类对象,在类对象的方法列表中查找方法,如果类对象方法列表中没有,就通过类对象的 superclass 去父类的类对象方法列表中找,直到找到为止,如果一直找到基类的类对象方法列表中都没找到,那就会报方法找不到的错误.当我们传入的对象是类对象时,会根据类对象的 isa 指针找到元类对象,在元类对象的方法类表中查找方法,如果元类对象的方法列表中没有的话,会通过元类对象的 superclass 去元类的父类对象中去找,直到找到为止,如果找到基类的元类都没找到,由于基类的元类对象的 superclass 指向基类的类对象,所以会在基类的类对象中查找方法,如果找的到就调用实例对象的该方法,如果找不到就报方法找不到的错误.所以当调用类方法时,如果没有实现该类方法,而实现了实例方法时,会调用该实例方法.
    总结下来就是 oc 的方法调用顺序就是:
    isa-->superclass-->superclass-->superclass...
    注意 1:这里我们需要注意基类的元类对象的 superclass 指向的是基类的类对象.
    注意 2: 类只能调用基类的实例方法,如果不是基类的实例方法,同样会报unrecognized selector sent to class ***的错入。比如下面的代码就会报这个错误

    @implementation NSObject(Test)
    //-(void)test{
    //    NSLog(@"Student = %@",self);
    //}
    @end
    @interface Person1 : NSObject
    @end
    @implementation Person1
    -(void)test{
        NSLog(@"Student = %@",self);
    }
    @end
    @interface Student : Person1
    @end
    @implementation Student
    @end
    @interface BigStudent : Student
    +(void)test;
    @end
    @implementation BigStudent
    @end
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            [BigStudent test];
        }
        return 0;
    }
    
    • 实例对象中的 isa 指向的是类对象的地址值吗?
      32 位系统是的,从 64 位系统开始,isa 需要一次位运算才能计算出真实地址
      实例对象的 isa & ISA_MASK = 类对象的地址值
    # if __arm64__
    #     define ISA_MASK     0x0000000ffffffff8ULL
    # elif __x86_64__
    #     define ISA_MASK     0x00007ffffffffff8ULL
    # endif
    
    • 类的内部结构


      类的内部结构.png
    • OC 的类的信息存放在哪里?
      1、成员变量的具体值,存放在实例对象中
      2、对象方法、属性、成员变量、协议信息存放在类对象中
      3、类方法存放在元类对象中

    • 类对象和元类对象什么时候初始话,什么时候释放
      类对象和元类对象在程序启动的时候就会加载进内存,在程序运行过程中始终存在,在程序终止时才释放.类对象和元类对象不论有没有使用到,都会在程序启动的时候加载进内存,类对象和元类对象在程序运行期间只有一份实例对象.

    相关文章

      网友评论

          本文标题:isa 和 superclass

          本文链接:https://www.haomeiwen.com/subject/utxyfhtx.html