如果一直到root class都沒有定位到SEL的實現,那么轉入消息轉發過程。
消息轉發流程圖
步驟一:動態解析
通過實現resolveInstanceMethod:/resolveClassMethod:方法,我們有機會為該未知消息(SEL)新增一個“處理方法”(IMP)。
這意味著在消息轉發前,你有機會通過class_addMethod給類動態添加一些方法
實際上返回值YES/NO無關緊要,只要你在resovle過程中新增過方法,就會觸發class_getMethodImplementation,其作用相當于重新啟動一次消息發送過程。
步驟二:備用接收者
通過實現-forwardingTargetForSelector:方法將消息(SEL)直接轉發給另一個對象(備用接收者),也就是在另一個對象(不能是nil或self)上重啟消息發送過程。
步驟三:完整轉發
通過實現-methodSignatureForSelector:提供方法簽名(即參數和返回值的類型信息)
可通過調用其他類的+instanceMethodSignatureForSelector:方法或其他對象的-methodSignatureForSelector:方法提供
也可通過+signatureWithObjCTypes:自行生成
生成的簽名將和原始消息一起打包到一個NSInvocation對象中。
通過操作NSInvocation對象的target、selector屬性可以方便地轉發,甚至轉發給另一個對象的另一個需要不同參數的SEL也是可以的
通過-getArgument:atIndex:和-setArgument:atIndex:可以操作方法調用傳入的參數
通過-getReturnValue:和-setReturnValue:可以直接操作方法invoke后的返回值。
通過調用-invoke方法重新啟動一個消息發送過程。
不調用invoke,吞掉這個消息(不做任何處理)
3 轉發的功能
轉發和多繼承
轉發模擬了繼承,所以可以用來為Objc程序提供類似多繼承的功能。轉發和多繼承的區別如下:
? 多繼承是將許多功能combine到一個對象中;
? 轉發則將功能分解到多個對象,并一種對消息發送者透明的方式將它們關聯起來;
代理/替代對象
場景描述:當你有一個對象,這個對象的設置由于需要處理大量數據非常耗時,所以更傾向于懶加載——在真正需要或系統空閑的時候來進行加載,這時你需要一個占位對象來使得應用的其他部分正常工作,這個占位對象的工作如下:
? 獲取關于待加載數據的描述信息
? 轉發消息時檢測對象是否創建并已加載完數據,據此決定創建對象、丟棄消息或轉發消息。
轉發和繼承
以下方法只考慮類繼承體系(不含轉發鏈);如需要對象表現得和繼承一樣,重寫它們并把轉發算法包括進來:
? -respondsToSelector: & +instancesRespondToSelector:
? -isKindOfClass: & -isMemberOfClass:
? -conformsToProtocol:
總結:
消息機制:繼承體系搜索 -> 消息轉發 ( 動態解析-> 快速轉發 -> 完整轉發 )
轉發和繼承(-respondsToSelector:等)、多繼承、代理