runtime簡(jiǎn)介
運(yùn)行時(shí)(Runtime)是指將數(shù)據(jù)類型的確定由編譯時(shí)推遲到了運(yùn)行時(shí),Runtime是一套比較底層的純C語(yǔ)言API, 屬于1個(gè)C語(yǔ)言庫(kù), 包含了很多底層的C語(yǔ)言API,平時(shí)編寫(xiě)的OC代碼,在程序運(yùn)行過(guò)程中,其實(shí)最終會(huì)轉(zhuǎn)換成Runtime的C語(yǔ)言代碼,Runtime是Object-C的幕后工作者,Object-C會(huì)使用到Runtime來(lái)創(chuàng)建類和對(duì)象,進(jìn)行消息發(fā)送和轉(zhuǎn)發(fā)
特性: 編寫(xiě)的代碼具有運(yùn)行時(shí)、動(dòng)態(tài)特性
isa
在我們初窺oc對(duì)象的時(shí)候了解到了isa,開(kāi)始的時(shí)候我們感覺(jué)它像是一個(gè)C的指針,現(xiàn)在我們想要細(xì)致的了解iOS的運(yùn)行時(shí)機(jī)制,我們需要更加細(xì)致的了解isa,對(duì)于我們了解runtime有很大的幫助。
在arm64之前,isa只是一個(gè)指針,保存對(duì)象地址或者類對(duì)象地址,但是在arm64架構(gòu)之后,蘋果對(duì)isa進(jìn)行了優(yōu)化,變成了一個(gè)union結(jié)構(gòu),通過(guò)位域方式來(lái)存儲(chǔ)更多的信息。
共用體:在進(jìn)行某些算法的C語(yǔ)言編程的時(shí)候,需要使幾種不同類型的變量存放到同一段內(nèi)存單元中。也就是使用覆蓋技術(shù),幾個(gè)變量互相覆蓋。這種幾個(gè)不同的變量共同占用一段內(nèi)存的結(jié)構(gòu),在C語(yǔ)言中,被稱作“共用體”類型結(jié)構(gòu),簡(jiǎn)稱共用體。
先看下objc_object源碼
我們知道OC對(duì)象的isa指針并不是直接指向類對(duì)象或者元類對(duì)象,而是需要&ISA_MASK通過(guò)位運(yùn)算才能獲取到類對(duì)象或者元類對(duì)象的地址。今天來(lái)探尋一下為什么需要&ISA_MASK才能獲取到類對(duì)象或者元類對(duì)象的地址,以及這樣的好處。源碼中isa_t是union類型, 可以看到共用體中有一個(gè)結(jié)構(gòu)體,結(jié)構(gòu)體內(nèi)部分別定義了一些變量,變量后面的值代表的是該變量占用多少個(gè)二進(jìn)制位,也就是位域技術(shù)。
isa詳解
要想學(xué)習(xí)Runtime,首先要了解它底層的一些常用數(shù)據(jù)結(jié)構(gòu),比如isa指針在arm64架構(gòu)之前,isa就是一個(gè)普通的指針,存儲(chǔ)著Class、Meta-Class對(duì)象的內(nèi)存地址,從arm64架構(gòu)開(kāi)始,對(duì)isa進(jìn)行了優(yōu)化,變成了一個(gè)共用體(union)結(jié)構(gòu),還使用位域來(lái)存儲(chǔ)更多的信息
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
# 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; \
uintptr_t has_assoc : 1; \
uintptr_t has_cxx_dtor : 1; \
uintptr_t shiftcls : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
uintptr_t magic : 6; \
uintptr_t weakly_referenced : 1; \
uintptr_t deallocating : 1; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 8
# define RC_ONE (1ULL<<56)
# define RC_HALF (1ULL<<7)
# else
# error unknown architecture for packed isa
# endif
可以簡(jiǎn)化為下面的圖

這里我們了解下每個(gè)字段的意義
nonpointer 代表iOS是普通的指針,存儲(chǔ)著Class、Meta-Class對(duì)象的內(nèi)存地址代表優(yōu)化過(guò),使用位域存儲(chǔ)更多的信息
has_assoc 是否有設(shè)置過(guò)關(guān)聯(lián)對(duì)象,如果沒(méi)有,釋放時(shí)會(huì)更快
has_cxx_dtor 是否有C++的析構(gòu)函數(shù)(.cxx_destruct),如果沒(méi)有,釋放時(shí)會(huì)更快
shiftcls 存儲(chǔ)著Class、Meta-Class對(duì)象的內(nèi)存地址信息
magic 用于在調(diào)試時(shí)分辨對(duì)象是否未完成初始化
weakly_referenced 是否有被弱引用指向過(guò),如果沒(méi)有,釋放時(shí)會(huì)更快
deallocating 對(duì)象是否正在釋放
extra_rc 里面存儲(chǔ)的值是引用計(jì)數(shù)器減1
has_sidetable_rc 引用計(jì)數(shù)器是否過(guò)大無(wú)法存儲(chǔ)在isa中如果為1,那么引用計(jì)數(shù)會(huì)存儲(chǔ)在一個(gè)叫SideTable的類的屬性中
isa需求
isa取值
00000101
&00000100
·-------------
00000100
isa進(jìn)行&操作,取哪位哪位值為1,結(jié)果有值相應(yīng)位為1無(wú)值為0
補(bǔ)充“>>”代表左移 ,例“1>>0”左移0位 0b000001 值位1 ,“1>>1左移1位 0b000010 值位2
isa取值
使用||操作,和&操作
設(shè)置位賦值為1
設(shè)置位賦值為1,先安位取反 00000100 = ~111101111,在安位&,
取反產(chǎn)操作“~”
00000101
&11111011
·-------------
00000001
isa位域
// 位域技術(shù),利用了每個(gè)字節(jié)的每一位
struct {
char tall : 1;
char rich : 1;
char handsome : 1;
} _tallRichHandsome; 一個(gè)
補(bǔ)充共用體
在進(jìn)行某些算法的C語(yǔ)言編程的時(shí)候,需要使幾種不同類型的變量存放到同一段內(nèi)存單元中。也就是使用覆蓋技術(shù),幾個(gè)變量互相覆蓋。這種幾個(gè)不同的變量共同占用一段內(nèi)存的結(jié)構(gòu),在C語(yǔ)言中,被稱作“共用體”類型結(jié)構(gòu),簡(jiǎn)稱共用體,也叫聯(lián)合體,用isa舉例子:isa所有數(shù)據(jù)都存在bits里面,下面的結(jié)構(gòu)體是用于理解的