+++
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ì)象。