什么是isa?
都说Objective-C是一门动态语言,为什么可以做到动态性呢?这其实跟isa
有很大的关系,在程序运行的时候,你可以通过修改一个实例对象的isa
来改变这个对象的类型,也可以通过isa
来给一个类动态添加方法,对象调用方法也离不开isa
和superclass
等等。
在iPhone 5s之前,苹果的A系列处理器是32位的,从此A7之后都是64位的。然后对应着代码里面的变化是,指针从4个字节变到8个字节。苹果为了提高性能,对isa
做了很大的调整。
32位版本的ojbc源码isa定义:
struct objc_object {
private:
uintptr_t isa;
//后面得代码省略
}
typedef unsigned long uintptr_t;
64位版本的objc源码isa定义:
struct objc_object {
private:
isa_t isa;
//后面得代码省略
}
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
};
#endif
};
# 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
#if SUPPORT_INDEXED_ISA
# if __ARM_ARCH_7K__ >= 2 || (__arm64__ && !__LP64__)
// armv7k or arm64_32
# define ISA_BITFIELD \
uintptr_t nonpointer : 1; \
uintptr_t has_assoc : 1; \
uintptr_t indexcls : 15; \
uintptr_t magic : 4; \
uintptr_t has_cxx_dtor : 1; \
uintptr_t weakly_referenced : 1; \
uintptr_t deallocating : 1; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 7
// Define SUPPORT_INDEXED_ISA=1 on platforms that store the class in the isa
// field as an index into a class table.
// Note, keep this in sync with any .s files which also define it.
// Be sure to edit objc-abi.h as well.
#if __ARM_ARCH_7K__ >= 2 || (__arm64__ && !__LP64__)
# define SUPPORT_INDEXED_ISA 1
#else
# define SUPPORT_INDEXED_ISA 0
#endif
很明显,在32位的时候,isa
就是一个普通指针,指向class
或者meta-class
;在64位时,isa
就是一个共用体union
了,里面有一个结构体,把8个字节64位分别作了不同的定义和用途。
- nonpointer占1位,0表示普通指针,存储着class或meta-class的内存;1表示优化过,使用位域存储着更多的信息。
- has_assoc占1位,表示是否设置过关联对象。
- has_cxx_dtor占1位,表示是否有c++析构函数。
- shiftcls占33位,存储着class或meta-class的内存地址。
- magic占6位,用于调试时分辨对象是否未完成初始化。
- weakly_referenced占1位,表示是否被弱引用指向过。
- deallocating占1位,表示对象是否正在释放。
- has_sidetable_rc占1位,如果为1,引用计数会存储在SideTable中。
- extra_rc占19位,存储着引用计数减1。
如何获取isa指针?
通过ISA_MASK
(0x0000000ffffffff8ULL)补码跟isa位域与运算可以得到,由于低地址的三位是0,所以class或meta-class的十六进制表示的地址最后一位要么是8(0x******8)要么是0(0x******0)
inline Class
objc_object::ISA()
{
assert(!isTaggedPointer());
#if SUPPORT_INDEXED_ISA
if (isa.nonpointer) {
uintptr_t slot = isa.indexcls;
return classForIndex((unsigned)slot);
}
return (Class)isa.bits;
#else
return (Class)(isa.bits & ISA_MASK);
#endif
}
为什么要有isa?
isa用来连接实例对象,类对象,元类对象之间的关系。isa中包含了对象的引用计数等核心信息。
- oc中方法的调用,消息机制
objc_msgSend
需要使用isa
和superclass
来完成。 - kvo的实现需要改变被观察者的类型,需要修改
isa
来完成。 - 实例对象的释放,需要用到
isa
中存储的引用计数来完成。