对象的 isa 指针指向哪里?

2020-04-06  本文已影响0人  游城十代2dai
  1. instance 对象的 isa 指针指向 class, 当调用对象方法时, isa 找到 class, 然后找到相应方法进行调用
  2. class 对象的 isa 指针指向 meta-class, 当调用类方法时, isa 找到 meta-class, 然后找到相应方法进行调用
  3. meta-class 对象的 isa 指针指向基类的 meta-class, 基类的指向自己

instance 对象调用流程: instance(subclass) 中的 isa 去 subclass 中找方法, 如果没找到就用 superclass 指针找到 subclass 的父类 superclass, 如果还没有就继续递进到 rootclass 中查找, 还是没有就在运行时报错误 crash "unrecognized selector sent to instance"

class 对象调用和 instance 对象一样, 只不过是去 meta-class 中查找类方法, 最后找不到, 就会从 root-meta-class 找, 如果还是找不到就去 rootclass 找对象方法, 还是没有就在运行时报错误 crash "unrecognized selector sent to class"

以下是对 isa 指针指向做的代码分析, 断点看下 isa 的地址

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

// 对象的 isa 指针指向哪里?
void about_isa(void);
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        about_isa();
    }
    return 0;
}

@interface Test : NSObject
@end
@implementation Test
@end

void about_isa() {
//    instance 对象的 isa 指针指向 class, 当调用对象方法时, isa 找到 class, 然后找到相应方法进行调用
//    class 对象的 isa 指针指向 meta-class, 当调用类方法时, isa 找到  meta-class, 然后找到相应方法进行调用
//    meta-class 对象的 isa 指针指向基类的 meta-class, 基类的指向自己
//    instance 对象调用流程: instance(subclass) 中的 isa 去 subclass 中找方法, 如果没找到就用 `superclass` 指针找到 subclass 的父类 superclass, 如果还没有就继续递进到 rootclass 中查找, 还是没有就在运行时报错误 crash "unrecognized selector sent to instance"
//    class 对象调用和 instance 对象一样, 只不过是去 meta-class 中查找类方法, 最后找不到, 就会从 root-meta-class 找, 如果还是找不到就去 rootclass 找**对象方法**, 还是没有就在运行时报错误 crash "unrecognized selector sent to class"
    
    /** lldb 调试一下 test 的 isa 指针地址
     * (lldb) p/x (long)test->isa
     * (long) $1 = 0x001d800100002119
     *
     * 与下面的 testClass 作对比发现 isa 的指针并不是指向类, 其实在 64bits 系统以后 isa 做了调整, 看源码搜索 "ISA_MASK" 就能找到一个宏定义, 将 isa & ISA_MASK 进行位运算才能得到实际的类, 由于我用的是 MacOS 所以对应的 ISA_MASK 为 0x00007ffffffffff8ULL , iOS 为 0x0000000ffffffff8ULL, meta-class 同理可证
     *
     * (lldb) p/x 0x00007ffffffffff8ULL & 0x001d800100002119
     * (unsigned long long) $7 = 0x0000000100002118
     */
    Test *test = Test.new;
    /** lldb 调试一下 testClass 的指针地址
     * (lldb) p/x testClass
     * (Class) $4 = 0x0000000100002118 Test
     *
     * lldb 调试一下, 由于 Class 类型没有暴露 isa 指针, 我需要做一个结构体强转, 这样得到 isa 的地址
     * (lldb) p/x testClass2->isa
     * (Class) $0 = 0x00000001000020f0
     */
    struct object_class {
        Class isa;
    };
    Class testClass = test.class;
    struct object_class *testClass2 = (__bridge struct object_class *)(testClass);
    
    /**
     * (lldb) p/x testMetaClass
     * (Class) $1 = 0x00000001000020f0
     * (lldb) p/x 0x00000001000020f0 & 0x00007ffffffffff8ULL
     * (unsigned long long) $2 = 0x00000001000020f0
     */
    Class testMetaClass = object_getClass(testClass);
    
    NSLog(@"%p - %p - %p - %p", test, testClass, testClass2, testMetaClass);
}

上一篇 下一篇

猜你喜欢

热点阅读