異變方法
Swift中class和struct都能定義方法。但是有一點(diǎn)區(qū)別的是默認(rèn)情況下达址,值類型屬性不能被自身的實(shí)例方法修改铃彰。
下面代碼運(yùn)行時(shí)會(huì)報(bào)錯(cuò)的趴俘,這個(gè)是因?yàn)閟truct里變量xy被自身修改了蜗巧。
當(dāng)我們?cè)谄淝懊婕恿藗€(gè)mutating訪問(wèn)掌眠,其就可以進(jìn)行自身的修改。這個(gè)我們探究源碼發(fā)現(xiàn)幕屹,其因?yàn)榧恿薽utating之后其傳如的里面會(huì)有一個(gè)@inout Point蓝丙,這個(gè)傳人的是地址,不是值望拖,所以其可以被修改渺尘。這個(gè)inout傳遞的就是當(dāng)前的地址。
Swift中的方法調(diào)度
oc是通過(guò)objc_messagesend來(lái)的靠娱,我們來(lái)看下Swift中的調(diào)度沧烈,我們通過(guò)斷點(diǎn)調(diào)試下掠兄,查看其內(nèi)部匯編是如何操作的像云。
下面打印X8可以得到x0的第一個(gè)8字節(jié),其是一個(gè)metdata蚂夕,如下:
teach函數(shù)的調(diào)用過(guò)程:找到Metadata迅诬,確定函數(shù)地址(metadata+偏移量),執(zhí)行函數(shù)婿牍。
swift里的方法是存在其類里面的函數(shù)表里侈贷,也就是sil_vtable,如下所示,因?yàn)槲覀冋{(diào)用了LGTeacher里的這三個(gè)方法等脂。
如果我們把Class改成Struct俏蛮,那方法是如何存儲(chǔ)的呢,通過(guò)下面的匯編調(diào)試可以知道其就是一個(gè)地址調(diào)用(也就是直接通過(guò)bl指令調(diào)用 )上遥。是因?yàn)橹殿愋蜎](méi)有繼承關(guān)系搏屑,定義的方法直接就是改結(jié)構(gòu)體的,所以編譯器會(huì)對(duì)其有個(gè)優(yōu)化粉楚,直接進(jìn)行調(diào)用辣恋。
當(dāng)我們用extension去擴(kuò)展一個(gè)類的話,其實(shí)其就是直接調(diào)用模软,不會(huì)插入到類里面伟骨,因?yàn)椴迦氲脑掃@樣對(duì)內(nèi)存消耗是十分大的,所以直接調(diào)用地址就可以燃异,可以節(jié)約內(nèi)存消耗携狭。
下面我們寫(xiě)的例子也可以看出,在class里有teach回俐,teach1逛腿,teach2壹瘟,這些事連續(xù)的地址,存放在sil_vtable里的鳄逾。用的extension定義的teach3稻轨,這個(gè)不是放在sil_vtable中,直接進(jìn)行值存儲(chǔ)的雕凹。
方法調(diào)度方式總結(jié)
NSObject子類和swift里的類一樣殴俱,對(duì)于Struct里的結(jié)構(gòu)體方法調(diào)度是值類型,所以有區(qū)別枚抵。
影響函數(shù)派發(fā)方式
1)final:添加了final關(guān)鍵字的函數(shù)無(wú)法被重寫(xiě)线欲,使用靜態(tài)派發(fā),不會(huì)在vtable中出現(xiàn)汽摹,且對(duì)objc運(yùn)行時(shí)不可見(jiàn)李丰。
2)dynamic:函數(shù)均可添加dynamic關(guān)鍵字,為非objc類和值類型的函數(shù)賦予動(dòng)態(tài)性逼泣,但派發(fā)方式還是函數(shù)表派發(fā)趴泌。
3)@objc:該關(guān)鍵字可以將Swift函數(shù)暴露給Objc運(yùn)行時(shí),依舊是函數(shù)表派發(fā)拉庶。(也就是轉(zhuǎn)換成了oc的調(diào)用方式 )
4)@objc + dynamic:消息派發(fā)的方式(也就是可以調(diào)用runtime的API)