isa指针本质
- 在arm64架构之前isa就是一个普通指针
- 在arm64架构之后,对isa进行了优化,变成了一个共用体
union
结构,还用了位域
来存储更多的信息
union isa_t
{
Class cls;
uintptr_t bits;
struct {
uintptr_t nonpointer :1;
uintptr_t has_assoc :1;
uintptr_t has_cxx_dtor :1;
uintptr_t shiftcls :33;
uintptr_t magic :6;
uintptr_t weakly_referenced :1;
uintptr_t deallocating :1;
uintptr_t has_sidetable_rc :1;
uintptr_t extra_rc :19;
};
};
- nonpointer
0,表示普通指针,存储着Class、Meta-Class对象的内存地址
1,代表优化过,使用位域存储更多的信息
- has_assoc
是否有设置过关联对象,如果没有,释放时会更快
- has_cxx_dtor
是否有C++的析构函数(.cxx_destruct),如果没有释放时会更快
- shiftcls
存放着Class、Meta-Class对象的内存地址信息
- magic
用于在调试的时候分辨对象是否未完成初始化
- weakly_referenced
是否有被弱引用指向过,如果没有,释放时会更快
- deallocating
对象是否正在释放
- has_sidetable_rc
1.引用计数器是否过大无法存储在isa中
2.如果为1,引用计数器会存储在SideTable的类属性中
- extra_rc
里面存储的值是引用计数器-1
isa的日常使用
isa的指向逻辑
- 实例对象的isa指向class
- class的isa指向meta-class
- meta-class的isa指向基类的meta-class
superclass的指向逻辑
- class的superclass指向父类的class;如果没有父类,superclass指向nil。(通过superclass找到父类的meta-class,直到找到类方法的实现进行调用)
- meta-class的superclass指向父类的meta-class,基类的meta-class的superclass指向基类class
isa和superclass的指向逻辑.png
方法调用逻辑
- 在调用对象方法的时候,通过实例对象的isa找到class,如果方法不存在,就通过superclass找父类,直到找到对象方法进行调用
- 当调用类方法的时候,通过class的isa找到meta-class,如果方法没知道到,就通过superclass找到父类的meta-class,直到找到类方法的实现进行调用;如果最后基类meta-class也没有找到类方法的实现,就通过superclass找到基类的class,在基类的class中查找同名的对象方法,如果找到了同名的对象方法就进行调用,如果没找到就会进入动态方法解析阶段,动态解析后仍然没有找到方法实现就会进入消息转发阶段,如果都没有处理就抛出NSInvalidArgumentException异常。
isa的内存地址和类对象的内存地址的关系
class的地址值:isa & ISA_MASK
objc4源码中ISA_MASK
的值
# if __arm64__
// ARM64 simulators have a larger address space, so use the ARM64e
// scheme even when simulators build for ARM64-not-e.
# define ISA_MASK 0x0000000ffffffff8ULL
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# else
# error unknown architecture for packed isa
# endif
通过模拟源码中的数据结构,定义一个新的结构体,通过强制转换得到结构体的值,可以验证源码中结构体的组成。
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
};
struct objc_object {
private:
isa_t isa;
};
#define FAST_DATA_MASK 0x00007ffffffffff8UL
struct class_data_bits_t {
friend objc_class;
// Values are the FAST_ flags above.
uintptr_t bits;
class_rw_t* data() const {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
};
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint16_t witness;
class_rw_ext_t *extAlloc(const class_ro_t *ro, bool deep = false);
};
struct class_rw_ext_t {
DECLARE_AUTHED_PTR_TEMPLATE(class_ro_t)
class_ro_t_authed_ptr<const class_ro_t> ro;
method_array_t methods;
property_array_t properties;
protocol_array_t protocols;
char *demangledName;
uint32_t version;
};
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;
};
面试:OC类的信息存放在哪里?
- 对象方法、属性、成员变量、协议,存放在class对象中
- 类方法,存放在meta-class对象中
- 成员变量的值存放在instance对象中
面试:isa指针指向哪里?
- instance对象的isa指向class对象
- class的isa指向meta-class对象
- meta-class的isa指向基类的meta-class对象
- 基类的meta-class的isa指向它自己
网友评论