runtime簡(jiǎn)介
運(yùn)行時(shí)(Runtime)是指將數(shù)據(jù)類型的確定由編譯時(shí)推遲到了運(yùn)行時(shí),Runtime是一套比較底層的純C語言API, 屬于1個(gè)C語言庫, 包含了很多底層的C語言API,平時(shí)編寫的OC代碼柑船,在程序運(yùn)行過程中,其實(shí)最終會(huì)轉(zhuǎn)換成Runtime的C語言代碼轻要,Runtime是Object-C的幕后工作者,Object-C會(huì)使用到Runtime來創(chuàng)建類和對(duì)象,進(jìn)行消息發(fā)送和轉(zhuǎn)發(fā)
特性: 編寫的代碼具有運(yùn)行時(shí)某残、動(dòng)態(tài)特性
isa
在我們初窺oc對(duì)象的時(shí)候了解到了isa,開始的時(shí)候我們感覺它像是一個(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),通過位域方式來存儲(chǔ)更多的信息裸扶。
共用體:在進(jìn)行某些算法的C語言編程的時(shí)候框都,需要使幾種不同類型的變量存放到同一段內(nèi)存單元中。也就是使用覆蓋技術(shù)呵晨,幾個(gè)變量互相覆蓋。這種幾個(gè)不同的變量共同占用一段內(nèi)存的結(jié)構(gòu)熬尺,在C語言中摸屠,被稱作“共用體”類型結(jié)構(gòu),簡(jiǎn)稱共用體粱哼。
先看下objc_object源碼
我們知道OC對(duì)象的isa指針并不是直接指向類對(duì)象或者元類對(duì)象季二,而是需要&ISA_MASK通過位運(yùn)算才能獲取到類對(duì)象或者元類對(duì)象的地址。今天來探尋一下為什么需要&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)開始,對(duì)isa進(jìn)行了優(yōu)化伴找,變成了一個(gè)共用體(union)結(jié)構(gòu)盈蛮,還使用位域來存儲(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)化過抖誉,使用位域存儲(chǔ)更多的信息
has_assoc 是否有設(shè)置過關(guān)聯(lián)對(duì)象,如果沒有穆役,釋放時(shí)會(huì)更快
has_cxx_dtor 是否有C++的析構(gòu)函數(shù)(.cxx_destruct)寸五,如果沒有,釋放時(shí)會(huì)更快
shiftcls 存儲(chǔ)著Class耿币、Meta-Class對(duì)象的內(nèi)存地址信息
magic 用于在調(diào)試時(shí)分辨對(duì)象是否未完成初始化
weakly_referenced 是否有被弱引用指向過梳杏,如果沒有,釋放時(shí)會(huì)更快
deallocating 對(duì)象是否正在釋放
extra_rc 里面存儲(chǔ)的值是引用計(jì)數(shù)器減1
has_sidetable_rc 引用計(jì)數(shù)器是否過大無法存儲(chǔ)在isa中如果為1,那么引用計(jì)數(shù)會(huì)存儲(chǔ)在一個(gè)叫SideTable的類的屬性中
isa需求
isa取值
00000101
&00000100
·-------------
00000100
isa進(jìn)行&操作十性,取哪位哪位值為1叛溢,結(jié)果有值相應(yīng)位為1無值為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語言編程的時(shí)候愕贡,需要使幾種不同類型的變量存放到同一段內(nèi)存單元中草雕。也就是使用覆蓋技術(shù),幾個(gè)變量互相覆蓋固以。這種幾個(gè)不同的變量共同占用一段內(nèi)存的結(jié)構(gòu)墩虹,在C語言中,被稱作“共用體”類型結(jié)構(gòu)憨琳,簡(jiǎn)稱共用體诫钓,也叫聯(lián)合體,用isa舉例子:isa所有數(shù)據(jù)都存在bits里面,下面的結(jié)構(gòu)體是用于理解的