Runtime objc4-756.2 isa_t与isa (1)

flag: 一年前写的runtime源码博客,今天看objc4已经更新到756.2版本了,接下来一个月内读完并写出对应的博客

前情提要:

runtime的源码版本: objc4-756.2
时间:2019-12-04

Runtime 可能并不是你看到的那样

在搜索引擎中搜索“Runtime”

baidu:

google runtime

google:

baidu runtime

这里边第一页的内容,挨个点进去,所有的人都会拿以下代码说事情:

struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;

但是这里边有

#if !__OBJC2__  如果不是Objective-C 2.0
OBJC2_UNAVAILABLE; Objective-C 2.0不可用

那我们现在是什么版本?Objective-C 2.0啊!!!

2006年7月它就发布了,虽然研究老的代码是有参考意义的,但是这么久远的实现应该被时间消逝的无影无踪了吧。有新的为什么不看?

通过Opensource我下载了objc4-723版本,也就是截止2018-11-23最新的runtime开源源码

常用结构体的变化

之前的版本定义:

// ??Class?id
typedef struct objc_class *Class; typedef struct objc_object *id;
// ??????
typedef struct objc_method *Method;
typedef struct objc_ivar *Ivar;
typedef struct objc_category *Category; typedef struct objc_property *objc_property_t;

现在的定义:

typedef struct objc_class *Class; typedef struct objc_object *id;
typedef struct method_t *Method;
typedef struct ivar_t *Ivar;
typedef struct category_t *Category; typedef struct property_t *objc_property_t;

objc_object

// 缩减版代码,public中都是方法,对结构的研究没有啥影响
struct objc_object {
private:
    isa_t isa;
}

objc_object问题

1,isa_t是个啥?

1.1 定义
// 缩减版代码,我们只留下 arm64下的代码,还有__x86_64__
union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h 这里和之前的723版本不同的是换成了宏,但内容本质上没有变化,可阅读行提高
    };
#endif
};

// 关于ISA_BITFIELD的定义

# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
#   define ISA_BITFIELD                                                      \
      uintptr_t nonpointer        : 1;                                       \
      uintptr_t has_assoc         : 1;                                       \
      uintptr_t has_cxx_dtor      : 1;                                       \
      uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
      uintptr_t magic             : 6;                                       \
      uintptr_t weakly_referenced : 1;                                       \
      uintptr_t deallocating      : 1;                                       \
      uintptr_t has_sidetable_rc  : 1;                                       \
      uintptr_t extra_rc          : 19
#   define RC_ONE   (1ULL<<45)
#   define RC_HALF  (1ULL<<18)

# elif __x86_64__
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x001f800000000001ULL
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
#   define ISA_BITFIELD                                                        \
       
        uintptr_t nonpointer        		: 1; 	// 1:64bit 0:32bit \
        uintptr_t has_assoc         		:1;	 	// 是否有关联引用或者曾经有关联引用\
        uintptr_t has_cxx_dtor      		: 1; 	// 是否有析构函数\
        uintptr_t shiftcls         		 	: 33; 	// 所属类的内存地址,isa的指向的\
        MACH_VM_MAX_ADDRESS 0x1000000000\
        uintptr_t magic             			: 6; 	// 是否初始化完成\
        uintptr_t weakly_referenced 	: 1; 	// 是否被弱引用或者曾经被弱引用\
        uintptr_t deallocating      		: 1; 	// 是否被释放中\
        uintptr_t has_sidetable_rc  		: 1; 	// 是否引用计数太大超出存储区域\
        uintptr_t extra_rc          			: 19; 	// 应用计数\
        
#   define RC_ONE   (1ULL<<56)
#   define RC_HALF  (1ULL<<7)

# else
#   error unknown architecture for packed isa
# endif

};

  • 1,这是一个union联合体,可以在内部写方法
  • 2,cls/ bits/ isa_t三部分
  • 3,一个描述性联合体,这是isa_t的核心,用它配合bits可以操作整个对象的内存空间
1.2 作用
  • cls是一个Class类型的,所以通过isa_t->cls 就可以获取到当前object的类对象,不用担心消息转发的方式有什么问题。

  • bitsuintptr_tunsigned long别名)类型,在64位系统里,64位,配合一些宏定义做位运算可以方便的获取到对应的信息,比如:在objc_object中有个 Class ISA()方法,内部实现的核心就是return (Class)(isa.bits & ISA_MASK);

  • ISA_MASK这样的宏还有很多,结构中的nonpointer has_assoc 等只可以操作独自负责的内存区域,但是bits可以操作整个对象的内存区域。

  • nonpointer 是对32位处理器的兼容,因为现在都是64位的,在32位的时代,isa就是一个指针地址.而64位的时代中,变成了isa_t,它是一个联合体,里边包含了64位数据上的对应的位操作.就是elif __x86_64__之下定义的这些参数.nonpointer也在其中.

  • 关于isa在64位处理器就变成了联合体的原因,是因为一个指针就占有64位的空间,8个字节,是非常浪费空间的,苹果在这个问题上使用了Tagged Pointer的内存处理技术,在后边我会单独拿出来写一篇博客.

objc_class

定义
//  缩减版代码
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() { 
        return bits.data();
    }

因为objc_class是继承自objc_object的,可以通过ISA()方法获取到对应的元类地址,这里也不用担心原有的消息转发流程问题。

  • superclass 根据注释我们可以看到出来它的作用就是原来isa指针的作用,指向父类的指针,注意这里是类对象的“父类”,最终会一层层指向到根元类,根元类也是一个objc_class对象,他的isa指针指向自己.这样在整个结构就形成了闭环.
  • cachecache_t类型,用来处理已经调用的方法缓存
  • class_data_bits_t 类型的bits是重点,这里边bits和前边isa_t的作用是一样的
  • class_rw_t与之对应的还有一个class_ro_t,前者是class在运行时状态的操作对象,它里边会持有对应的class_ro_t,可读可写。后者是编译时生成的class类型,只读。这两者的详细区别下篇文章解释

常见场景解读

我们经常看到解释isa的一个图

12

objc_object objc_class在objc4源码中的定义我们已经在上边解读了

对应图中的关系如下:

duiying
这样我们可以看出isa指向的是这个对象所属的类,(很多文章说是父类,其实是不准确的).为什么这么说

我们可以看objct.mmsuperclass的定义


+ (Class)superclass {
    return self->superclass;
}

- (Class)superclass {
    return [self class]->superclass;
}

所以这句话是不准确的,对于isa指向的描述用指向本对象所属类是比较好的.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值