欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

isa详解

程序员文章站 2024-03-23 22:37:16
...

在arm64架构之前,isa就是一个普通的指针,存储着Class、Meta-Class对象的内存地址

从arm64架构开始,对isa进行了优化,变成了一个共用体(union)结构,还使用位域来存储更多的信息

isa详解

nonpointer

0,代表普通的指针,存储着Class、Meta-Class对象的内存地址

1,代表优化过,使用位域存储更多的信息

has_assoc

是否有设置过关联对象,如果没有,释放时会更快

has_cxx_dtor

是否有C++的析构函数(.cxx_destruct),如果没有,释放时会更快

shiftcls

存储着Class、Meta-Class对象的内存地址信息

magic

用于在调试时分辨对象是否未完成初始化

weakly_referenced

是否有被弱引用指向过,如果没有,释放时会更快

deallocating

对象是否正在释放

extra_rc

里面存储的值是引用计数器减1

has_sidetable_rc

引用计数器是否过大无法存储在isa中 如果为1,那么引用计数会存储在一个叫SideTable的类的属性中

所以我们在源码中看到类对象,元类对象的实际地址值都要用isa地址& ISA_MASK 一个值,这就是位运算来获得实际shiftcls值。

#   define ISA_MASK        0x00007ffffffffff8ULL

由isa我们重新来看class结构

isa详解isa详解

class_rw_t

由class_data_bits_t & MASK值获得class_rw_t,

class_rw_t里面的methods、properties、protocols是二维数组,是可读可写的,包含了类的初始内容、分类的内容

isa详解

class_ro_t

class_ro_t里面的baseMethodList、baseProtocols、ivars、baseProperties是一维数组,是只读的,包含了类的初始内容

isa详解

method_t

method_t是对方法\函数的封装

isa详解

SEL代表方法\函数名,一般叫做选择器,底层结构跟char *类似

  1. 可以通过@selector()和sel_registerName()获得
  2. 可以通过sel_getName()和NSStringFromSelector()转成字符串
  3. 不同类中相同名字的方法,所对应的方法选择器是相同的

types包含了函数返回值、参数编码的字符串

一般我们正常写的函数都默认包含了两个参数(self,SEL),我们写申明一个test方法,

- (void)test;


- (void)test{
}

打印出来types就变成 aaa@qq.com:8,v代表返回值,16为总的字节,@代表self,0表示从第0哥开始,:代表SEL

isa详解isa详解

cache

Class内部结构中有个方法缓存(cache_t),用散列表(哈希表)来缓存曾经调用过的方法,可以提高方法的查找速度

isa详解

缓存原理为地址值& _mask 为索引,SEL作为key,用空间换时间,当这个索引存在时,就会到索引减1那,还有值时,继续减1,为0时 则扩充_mask 并清空之前的数据,因为&_mask 得到的值肯定会小于等于_mask,这样就不会越界。

bucket_t * cache_t::find(SEL s, id receiver)
{
    assert(s != 0);

    bucket_t *b = buckets();
    mask_t m = mask();
    mask_t begin = cache_hash(s, m);
    mask_t i = begin;
    do {
        if (b[i].sel() == 0  ||  b[i].sel() == s) {
            return &b[i];
        }
    } while ((i = cache_next(i, m)) != begin);

    // hack
    Class cls = (Class)((uintptr_t)this - offsetof(objc_class, cache));
    cache_t::bad_cache(receiver, (SEL)s, cls);
}


static inline mask_t cache_hash(SEL sel, mask_t mask) 
{
    return (mask_t)(uintptr_t)sel & mask;
}