+++
Categories = ["iOS",]
Tags = ["iOS","error",]
date = "2014-06-22T19:59:51+08:00"
title = "什么時(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í)際所屬的類题涨,然后在該類中的方法列表以及其父類方法列表中尋找方法運(yùn)行,如果总滩,在最頂層的父類中依然找不到相應(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ù)和返回值類型赘风。
如果-methodSignatureForSelector:
返回nil夹囚,Runtime則會(huì)發(fā)出-doesNotRecognizeSelector:
消息,程序這時(shí)也就掛掉了邀窃。
如果返回了一個(gè)函數(shù)簽名荸哟,Runtime就會(huì)創(chuàng)建一個(gè)NSInvocation對(duì)象并發(fā)送-forwardInvocation:
消息給目標(biāo)對(duì)象。