什么是isa奕剃?
都說Objective-C是一門動(dòng)態(tài)語言恩沛,為什么可以做到動(dòng)態(tài)性呢呀枢?這其實(shí)跟isa
有很大的關(guān)系祈搜,在程序運(yùn)行的時(shí)候较店,你可以通過修改一個(gè)實(shí)例對(duì)象的isa
來改變這個(gè)對(duì)象的類型,也可以通過isa
來給一個(gè)類動(dòng)態(tài)添加方法容燕,對(duì)象調(diào)用方法也離不開isa
和superclass
等等梁呈。
在iPhone 5s之前,蘋果的A系列處理器是32位的蘸秘,從此A7之后都是64位的官卡。然后對(duì)應(yīng)著代碼里面的變化是,指針從4個(gè)字節(jié)變到8個(gè)字節(jié)醋虏。蘋果為了提高性能寻咒,對(duì)isa
做了很大的調(diào)整。
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位的時(shí)候毛秘,isa
就是一個(gè)普通指針,指向class
或者meta-class
阻课;在64位時(shí)叫挟,isa
就是一個(gè)共用體union
了,里面有一個(gè)結(jié)構(gòu)體限煞,把8個(gè)字節(jié)64位分別作了不同的定義和用途抹恳。
- nonpointer占1位,0表示普通指針署驻,存儲(chǔ)著class或meta-class的內(nèi)存奋献;1表示優(yōu)化過健霹,使用位域存儲(chǔ)著更多的信息。
- has_assoc占1位秽荞,表示是否設(shè)置過關(guān)聯(lián)對(duì)象骤公。
- has_cxx_dtor占1位,表示是否有c++析構(gòu)函數(shù)扬跋。
- shiftcls占33位阶捆,存儲(chǔ)著class或meta-class的內(nèi)存地址。
- magic占6位钦听,用于調(diào)試時(shí)分辨對(duì)象是否未完成初始化洒试。
- weakly_referenced占1位,表示是否被弱引用指向過朴上。
- deallocating占1位垒棋,表示對(duì)象是否正在釋放。
- has_sidetable_rc占1位痪宰,如果為1叼架,引用計(jì)數(shù)會(huì)存儲(chǔ)在SideTable中。
- extra_rc占19位衣撬,存儲(chǔ)著引用計(jì)數(shù)減1乖订。
如何獲取isa指針?
通過ISA_MASK
(0x0000000ffffffff8ULL)補(bǔ)碼跟isa位域與運(yùn)算可以得到具练,由于低地址的三位是0乍构,所以class或meta-class的十六進(jìn)制表示的地址最后一位要么是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用來連接實(shí)例對(duì)象炮叶,類對(duì)象,元類對(duì)象之間的關(guān)系美澳。isa中包含了對(duì)象的引用計(jì)數(shù)等核心信息陵究。
- oc中方法的調(diào)用眠饮,消息機(jī)制
objc_msgSend
需要使用isa
和superclass
來完成。 - kvo的實(shí)現(xiàn)需要改變被觀察者的類型畔乙,需要修改
isa
來完成君仆。 - 實(shí)例對(duì)象的釋放,需要用到
isa
中存儲(chǔ)的引用計(jì)數(shù)來完成牲距。