day 3 isa 指针 和 superclass 指针

day 3 isa 指针 和 superclass 指针

IOS小彩虹2021-08-17 22:28:18140A+A-

对象的isa 指向什么?

方法调用的本质是 runtime 的 objc_megSend(消息转发)

Person *person = [[Person alloc] init];
[person personInstanceMethod];
// ((void (*)(id, SEL))(void *)objc_msgSend)((id)person, sel_registerName("personInstanceMethod"));
// objc_msgSend(person, @selector(personInstanceMethod));

[Person personClassMethod];
// ((void (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("personClassMethod"));
// objc_msgSend([Person class], @selector(personClassMethod));
  1. instance 对象的isa 指向 class
    • 当调用实例方法时,通过instance 的 isa 找到 class,最后找到对象方法的实现并调用
  2. class 的 isa 指向 meta-class
    • 当调用类方法时,通过class 的isa 找到 meta-class,最后找到类方法的实现并调用
  3. meta-class 的 isa 指向基类的 meta-class

class 的superClass指针

肯定是跟继承有关系

@interface Person: NSObject
@interface Student: Person
  1. 当 Student 的 instance 对象调用 Person 的对象方法时,会先通过 isa 找到Student 的class类对象,然后通过 superclass 找到 Person 的 class 类对象,最后找到对象方法的实现并调用;
  2. 当 Student 的 instance 对象调用 NSObject 的对象方法时,会先通过 isa 找打Student 的 class 类对象, 然后通过 superclass 找打 Person 的 class 类对象, 再通过 superclass 找到 NSObject 的 class 类对象, 最后找到对象方法的实现并调用

meta-class 对象的 superClass 指针

  1. 当 Student 的 class 要调用 Person 的类方法时,会想通过 isa 找到 Student 的 meta-class 元类对象, 然后通过 superclass 找到 Person 的 meta-class 元类对象,最后找到类方法的实现并调用;
  2. 当 Student 的 class 要调用 NSObject 的类方法时,会通过 isa 找到 Student 的 meta-class 元类对象, 然后通过 superclass 找到 Person 的 meta-class元类对象,然后通过 superclass 找到NSObject 的 meta-class 元类对象, 最后找到类方法的实现并调用

isa 和 superclass 总结

1194012-d7b097e86f9e488d.png

  1. instance实例对象 的isa 指向class类对象
  2. class类对象 的isa 指向 meta-class元类对象
  3. meta-class元类对象 的 isa 指向基类的 meta-class元类对象
    • 基类 meta-class 的 isa 指向它本身
  4. class 的superclass 指向它父类的 class
    • 如果没有父类,则指向nil
  5. meta-class 的superclass 指向父类的meta-class
    • [重点] 基类的meta-class 的superclass 指向 基类的 class(为什么?)
    • 因为 OC 中的方法是 msgSend,并不关心是否是类方法还是实例方法,只是匹配方法名称,所以基类的 class 对象中如果有实例方法名和调用的类方法名重名,也照样能调用
  6. instance 调用方法轨迹
    • isa 找到 class,方法不存在,通过superclass 找父类
  7. class 调用方法轨迹
    • isa 找到meta-class,方法不存在,通过superclass 找父类

关于 isa 指向问题

// 
# if __arm64__
#     define ISA_MASK        0x007ffffffffffff8ULL
#   else
#     define ISA_MASK        0x0000000ffffffff8ULL
  • 在32位机器上,instance 对象的 isa 直接指向的是就是类对象的实现
  • 在64位机器上,instance 对象的 isa 需要先进行一次与运算ISA_MASK,其结果指向的是类对象的实现
  • 0xxxxx & 0x007ffffffffffff8

关于superclass 指向问题

  • 子类的superclass 直接指向的就是 父类的实现,不会经过任何运算

类对象源码

struct objc_object {
private:
    isa_t isa;
}
// 最新版本中的体现
struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
	  class_rw_t *data() const {
        return bits.data();
    }
}
// class_readwrite_table {}
struct class_rw_t {
	  // readonly - 这里包含了 类名及成员变量信息
	  const class_ro_t *ro() const {
        auto v = get_ro_or_rwe();
        if (slowpath(v.is<class_rw_ext_t *>())) {
            return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro;
        }
        return v.get<const class_ro_t *>(&ro_or_rw_ext);
    }
	  // 方法列表信息
    const method_array_t methods() const {
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->methods;
        } else {
            return method_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseMethods()};
        }
    }
	  // 属性列表信息
    const property_array_t properties() const {
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->properties;
        } else {
            return property_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProperties};
        }
    }
	  // 代理信息
    const protocol_array_t protocols() const {
        auto v = get_ro_or_rwe();
        if (v.is<class_rw_ext_t *>()) {
            return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->protocols;
        } else {
            return protocol_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProtocols};
        }
    }
}

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize; // 实例变量需要的内存大小
#ifdef __LP64__
    uint32_t reserved;
#endif

    union {
        const uint8_t * ivarLayout;
        Class nonMetaclass;
    };

    explicit_atomic<const char *> name; // 类名
    // With ptrauth, this is signed if it points to a small list, but
    // may be unsigned if it points to a big list.
    void *baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars; // 成员变量信息

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;
}

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1
本网站由 提供CDN/云存储服务

联系我们