-
什么時(shí)候會(huì)報(bào)unrecognized selector的異常盈罐?
簡(jiǎn)單來(lái)說(shuō):
當(dāng)調(diào)用該對(duì)象上某個(gè)方法,而該對(duì)象上沒(méi)有實(shí)現(xiàn)這個(gè)方法的時(shí)候藤乙, 可以通過(guò)“消息轉(zhuǎn)發(fā)”進(jìn)行解決。
objc是動(dòng)態(tài)語(yǔ)言,每個(gè)方法在運(yùn)行時(shí)會(huì)被動(dòng)態(tài)轉(zhuǎn)為消息發(fā)送遭笋,即:objc_msgSend(receiver, selector)
。
objc在向一個(gè)對(duì)象發(fā)送消息時(shí)徒探,runtime庫(kù)會(huì)根據(jù)對(duì)象的isa指針找到該對(duì)象實(shí)際所屬的類(lèi)瓦呼,然后在該類(lèi)中的方法列表以及其父類(lèi)方法列表中尋找方法運(yùn)行,如果测暗,在最頂層的父類(lèi)中依然找不到相應(yīng)的方法時(shí)央串,程序在運(yùn)行時(shí)會(huì)掛掉并拋出異常unrecognized selector sent to XXX 。
但是在這之前碗啄,objc的運(yùn)行時(shí)會(huì)給出三次拯救程序崩潰的機(jī)會(huì):
- Method resolution
objc運(yùn)行時(shí)會(huì)調(diào)用
+resolveInstanceMethod:
或者+resolveClassMethod:
,讓你有機(jī)會(huì)提供一個(gè)函數(shù)實(shí)現(xiàn)质和。
如果你添加了函數(shù),那運(yùn)行時(shí)系統(tǒng)就會(huì)重新啟動(dòng)一次消息發(fā)送的過(guò)程,
否則 ,運(yùn)行時(shí)就會(huì)移到下一步,消息轉(zhuǎn)發(fā)(Message Forwarding)
。
- Fast forwarding
如果目標(biāo)對(duì)象實(shí)現(xiàn)了
-forwardingTargetForSelector:
,Runtime 這時(shí)就會(huì)調(diào)用這個(gè)方法,給你把這個(gè)消息轉(zhuǎn)發(fā)給其他對(duì)象的機(jī)會(huì).
只要這個(gè)方法返回的不是nil和self稚字,整個(gè)消息發(fā)送的過(guò)程就會(huì)被重啟饲宿,當(dāng)然發(fā)送的對(duì)象會(huì)變成你返回的那個(gè)對(duì)象。
否則胆描,就會(huì)繼續(xù)Normal Fowarding
瘫想。 這里叫Fast,只是為了區(qū)別下一步的轉(zhuǎn)發(fā)機(jī)制昌讲。因?yàn)檫@一步不會(huì)創(chuàng)建任何新的對(duì)象殿托,但下一步轉(zhuǎn)發(fā)會(huì)創(chuàng)建一個(gè)NSInvocation對(duì)象,所以相對(duì)更快點(diǎn)剧蚣。
- Normal forwarding
這一步是Runtime最后一次給你挽救的機(jī)會(huì)支竹。
首先它會(huì)發(fā)送-methodSignatureForSelector:
,消息獲得函數(shù)的參數(shù)和返回值類(lèi)型。
如果-methodSignatureForSelector:
返回nil,Runtime則會(huì)發(fā)出-doesNotRecognizeSelector:
消息鸠按,程序這時(shí)也就掛掉了礼搁。
如果返回了一個(gè)函數(shù)簽名,Runtime就會(huì)創(chuàng)建一個(gè)NSInvocation對(duì)象并發(fā)送-forwardInvocation:
消息給目標(biāo)對(duì)象目尖。