一 面試題
1.講一下 OC 的消息機(jī)制
OC中的方法調(diào)用其實(shí)都是轉(zhuǎn)成了objc_msgSend函數(shù)的調(diào)用,給receiver(方法調(diào)用者)發(fā)送了一條消息(selector方法名)
objc_msgSend底層有3大階段
消息發(fā)送(當(dāng)前類、父類中查找)、動(dòng)態(tài)方法解析、消息轉(zhuǎn)發(fā)
2. 什么是Runtime?平時(shí)項(xiàng)目中有用過(guò)么?
OC是一門(mén)動(dòng)態(tài)性比較強(qiáng)的編程語(yǔ)言,允許很多操作推遲到程序運(yùn)行時(shí)再進(jìn)行
OC的動(dòng)態(tài)性就是由Runtime來(lái)支撐和實(shí)現(xiàn)的,Runtime是一套C語(yǔ)言的API,封裝了很多動(dòng)態(tài)性相關(guān)的函數(shù)
平時(shí)編寫(xiě)的OC代碼,底層都是轉(zhuǎn)換成了Runtime API進(jìn)行調(diào)用
3.runtime具體應(yīng)用
利用關(guān)聯(lián)對(duì)象(AssociatedObject)給分類添加屬性
遍歷類的所有成員變量(修改textfield的占位文字顏色、字典轉(zhuǎn)模型、自動(dòng)歸檔解檔)
交換方法實(shí)現(xiàn)(交換系統(tǒng)的方法)
利用消息轉(zhuǎn)發(fā)機(jī)制解決方法找不到的異常問(wèn)題
7.說(shuō)說(shuō)什么是runtime
1.OC 是一個(gè)全動(dòng)態(tài)語(yǔ)言,OC 的一切都是基于 Runtime 實(shí)現(xiàn)的平時(shí)編寫(xiě)的OC代碼, 在程序運(yùn)行過(guò)程中, 其實(shí)最終都是轉(zhuǎn)成了runtime的C語(yǔ)言代碼, runtime算是OC的幕后工作者
比如:
OC :[[Person alloc] init]runtime :objc_msgSend(objc_msgSend("Person","alloc"),"init")
2.runtime是一套比較底層的純C語(yǔ)言API, 屬于1個(gè)C語(yǔ)言庫(kù), 包含了很多底層的C語(yǔ)言API
3.runtimeAPI的實(shí)現(xiàn)是用 C++ 開(kāi)發(fā)的(源碼中的實(shí)現(xiàn)文件都是mm),是一套蘋(píng)果開(kāi)源的框架
1.背景知識(shí)
1.1 OC的方法調(diào)用流程
下面以實(shí)例對(duì)象調(diào)用方法[blackDog walk]為例描述方法調(diào)用的流程:
1、編譯器會(huì)把`[blackDog walk]`轉(zhuǎn)化為`objc_msgSend(blackDog,SEL)`,SEL為@selector(walk)。
2、Runtime會(huì)在blackDog對(duì)象所對(duì)應(yīng)的Dog類的方法緩存列表里查找方法的SEL
3、如果沒(méi)有找到,則在Dog類的方法分發(fā)表查找方法的SEL。(類由對(duì)象isa指針指向,方法分發(fā)表即methodList)
4、如果沒(méi)有找到,則在其父類(設(shè)Dog類的父類為Animal類)的方法分發(fā)表里查找方法的SEL(父類由類的superClass指向)
5、如果沒(méi)有找到,則沿繼承體系繼續(xù)下去,最終到達(dá)NSObject類。
6、如果在234的其中一步中找到,則定位了方法實(shí)現(xiàn)的入口,執(zhí)行具體實(shí)現(xiàn)
7、如果最后還是沒(méi)有找到,會(huì)面臨兩種情況:
(1) 如果是使用`[blackDog walk]`的方式調(diào)用方法
(2) 使用`[blackDog performSelector:@selector(walk)]`的方式調(diào)用方法
2,消息轉(zhuǎn)發(fā)流程
1、動(dòng)態(tài)方法解析接收到未知消息時(shí)(假設(shè)blackDog的walk方法尚未實(shí)現(xiàn)),runtime會(huì)調(diào)用+resolveInstanceMethod:(實(shí)例方法)或者+resolveClassMethod:(類方法)
2、備用接收者如果以上方法沒(méi)有做處理,runtime會(huì)調(diào)用- (id)forwardingTargetForSelector:(SEL)aSelector方法。如果該方法返回了一個(gè)非nil(也不能是self)的對(duì)象,而且該對(duì)象實(shí)現(xiàn)了這個(gè)方法,那么這個(gè)對(duì)象就成了消息的接收者,消息就被分發(fā)到該對(duì)象。適用情況:通常在對(duì)象內(nèi)部使用,讓內(nèi)部的另外一個(gè)對(duì)象處理消息,在外面看起來(lái)就像是該對(duì)象處理了消息。比如:blackDog讓女朋友whiteDog來(lái)接收這個(gè)消息
3、完整消息轉(zhuǎn)發(fā)在- (void)forwardInvocation:(NSInvocation*)anInvocation方法中選擇轉(zhuǎn)發(fā)消息的對(duì)象,其中anInvocation對(duì)象封裝了未知消息的所有細(xì)節(jié),并保留調(diào)用結(jié)果發(fā)送到原始調(diào)用者。比如:blackDog將消息完整轉(zhuǎn)發(fā)給主人dogOwner來(lái)處理