實例方法存在類對象中
類方法存在元類對象中(元類其實也是壹個類對象)
我們先看下類對象的結構布局
我們看到壹個類對象就是壹個結構體繼承與objc_object結構體,我們以前的文章中分析過objc_object結構體,這裏簡單的說壹下objc_object, objc_object裏面有壹個isa是壹個***用體.裏面有壹個結構體使用位域來存儲更多的信息.
superclass是指向父類的指針
cache方法的緩存列表
bits& FAST_DATA_MASK的到class_rw_t結構體
在class_rw_t中 methods就是方法的緩存類表
我們以前討論分類的的時候也分析過method_array_t methods;結構
methods是壹個二維數組, 數組裏面的元素是分類的的方法類表
[
[分類方法1a方法,分類方法1b方法],
[分類方法2a方法,分類方法2b方法]
]
我們給壹個對象發消息的時候就會找到methods這個數組裏面然後緩存到cache中,就算給壹個對象調用父類的方法也會緩存到cache中的_buckets, 當往_buckets緩存bucket_t的時候_buckets會檢查是否需要擴容,需要擴容就會清空所有元素然後,在緩存進來.(這個時候以前的緩存就沒有了)
我看到cache結構體中_buckets是壹個數組裏面是bucket_t結構體_key就是方法名字_buckets就相當於壹個離散列表(類似字典)
x0, 寄存器裏面存的是receiver消息接受者
b.le LNilOrTagged //如果receiver為nil跳轉到LNilOrTagged
b.eq LReturnZero // nil check
ret (表示return)
如果對象為nil就return
如果對象不為nil就走到CacheLookup 在緩存中尋找
CacheHit 命中緩存 結果是直接調用方法或者返回imp指針
CheckMiss在緩存中沒有找到
因為CacheLookup NORMAL傳的值是NORMAL 這裏我們暫時只分析__objc_msgSend_uncached
我們再分析MethodTableLookup 發現是個宏
bl __class_lookupMethodAndLoadCache3 意思是跳轉到__class_lookupMethodAndLoadCache3這個方法.
接下來就來到了lookUpImpOrForward
我們分析壹下_class_resolveMethod
如果是實例方法則會調用 _class_resolveInstanceMethod.
我們分析壹下_class_resolveInstanceMethod方法SEL_resolveInstanceMethod 是+ (BOOL)resolveInstanceMethod:(SEL)sel 通過objc_msgSend調用這個類方法, 我們可以重寫這個類方法, 並且在類方法中 動態添加方法
如果我們動態解析沒有做事情 就會來到消息轉發_objc_msgForward_impcache這個imp我們發現在匯編中找到,但是經過分析是沒有源碼的,這裏暫不分析匯編
下面列出動態轉發的幾個方法.
在消息轉發階段如果-forwardingTargetForSelector沒有實現,就會調用- methodSignatureForSelector方法自己返回方法簽名,
然後調用-forwardInvocation返回壹個NSInvocation對象
補充壹點如果 消息轉發階段這個消息是類方法就會調用+forwardingTargetForSelector,+ methodSignatureForSelector
,+ forwardInvocation (雖然沒有暴露出api)
不管是類方法還是對象方法在消息轉發階段, 其實都是消息接受者調用以上的方法.(這樣就可以理解為啥 ,對象方法調用-號類方法調用+號了 因為消息接受者不同)
1消息發送
2動態方法解析
3消息轉發