Runtime objc4-756.2 isa_t与isa
Posted Jsen_Wang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Runtime objc4-756.2 isa_t与isa相关的知识,希望对你有一定的参考价值。
flag: 一年前写的runtime源码博客,今天看objc4已经更新到756.2版本了,接下来一个月内读完并写出对应的博客
前情提要:
runtime的源码版本: objc4-756.2
时间:2019-12-04
Runtime 可能并不是你看到的那样
在搜索引擎中搜索“Runtime”
baidu:
google:
这里边第一页的内容,挨个点进去,所有的人都会拿以下代码说事情:
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
的类对象,不用担心消息转发的方式有什么问题。 -
bits
是uintptr_t
(unsigned 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指针指向自己.这样在整个结构就形成了闭环.cache
是cache_t
类型,用来处理已经调用的方法缓存class_data_bits_t
类型的bits
是重点,这里边bits
和前边isa_t
的作用是一样的class_rw_t
与之对应的还有一个class_ro_t
,前者是class在运行时状态的操作对象,它里边会持有对应的class_ro_t
,可读可写。后者是编译时生成的class类型,只读。这两者的详细区别下篇文章解释
常见场景解读
我们经常看到解释isa的一个图
objc_object
objc_class
在objc4源码中的定义我们已经在上边解读了
对应图中的关系如下:
这样我们可以看出isa
指向的是这个对象所属的类,(很多文章说是父类,其实是不准确的).为什么这么说
我们可以看objct.mm
中superclass
的定义
+ (Class)superclass
return self->superclass;
- (Class)superclass
return [self class]->superclass;
所以这句话是不准确的,对于isa
指向的描述用指向本对象所属类
是比较好的.
以上是关于Runtime objc4-756.2 isa_t与isa的主要内容,如果未能解决你的问题,请参考以下文章
NSObjectClass objc_class objc_objct isa_t
NSObjectClass objc_class objc_objct isa_t