類方法存在於元類中(元類實際上是壹個類對象)。
我們先來看類對象的結構布局。
我們看到壹個類對象是結構繼承,壹個對象結構。我們在以前的文章中分析了objc_object結構。這裏簡單說壹下objc_object,objc_object。objc _ object中有壹個ISA,它是壹個* * *對象。有壹種結構使用壹個位字段來存儲更多的信息。
超類是指向父類的指針。
緩存方法的緩存列表
比特& amp從FAST_DATA_MASK到class_rw_t的結構
在class_rw_t中,methods是方法的緩存類表。
我們之前討論分類的時候,也分析了method_array_t方法;結構
Methods是壹個二維數組,數組中的元素是分類的方法類表。
[
【分類方法1a方法,分類方法1b方法】,
[分類方法2a方法,分類方法2b方法]
]
當我們向壹個對象發送消息時,我們將找到方法數組並將其緩存在緩存中。即使我們調用壹個對象的父類的方法,它也會被緩存在緩存中的_buckets中。當我們在_buckets中緩存bucket_t時,_buckets會檢查是否需要擴展。如果需要展開,會清空所有元素。然後,它將被緩存。(這時候之前的緩存就沒了。)
我看到緩存結構中的_buckets是壹個數組,其中bucket_t structure _key是方法名_buckets相當於壹個離散列表(類似於字典)。
X0,接收方消息receiver存儲在寄存器中。
B.le LNilOrTagged //如果接收端為零,則跳轉到LNilOrTagged。
b.eq LReturnZero // nil check
Ret(返回)
如果對象為零,則返回。
如果對象不為空,則轉到CacheLookup並在緩存中查找它。
CacheHit命中緩存,結果是直接調用方法或者返回imp指針。
在緩存中找不到CheckMiss。
因為CacheLookup NORMAL傳遞的值是正常的,所以這裏我們暫時只分析__objc_msgSend_uncached。
我們再次分析MethodTableLookup,發現它是壹個宏。
BL _ _ class _ LookupMethodAndLoadCache 3表示跳轉到_ _ class _ LookupMethodAndLoadCache 3的方法。
然後我們來到lookUpImpOrForward。
我們來分析_class_resolveMethod。
如果是實例方法,會調用_class_resolveInstanceMethod。
我們來分析壹下_ class _ resolveInstanceMethod SEL _ resolveInstanceMethod is+(bool)resolveInstanceMethod:(SEL)SEL通過objc_msgSend調用這個類方法,我們可以重寫這個類方法,並動態地給類方法添加方法。
如果動態分析沒有做的事情,就會來到消息forwarding _ objc _ msg forward _ imp cache,這個消息是我們在匯編中找到的,但是分析後沒有源代碼,這裏暫時不分析匯編。
下面列出了幾種動態轉發的方法。
在消息轉發階段,如果未實現-forwardingTargetForSelector,將調用-methodSignatureForSelector方法返回方法簽名本身。
然後調用-forwardInvocation返回壹個NSInvocation對象。
另外,如果消息是消息轉發階段的類方法,+ForwardingTargetForSelector,+MethodSignatureForSelector將被調用。
,+forwardInvocation(雖然沒有公開api)
在消息轉發階段無論是類方法還是對象方法,實際上都是消息接收方調用上述方法。(這樣妳就能理解為什麽對象方法調用了——類方法調用+是因為消息接收方不同。)
1消息發送
2動態方法分析
3消息轉發