The Complete Objective-C Messaging Flow
It is time for me to clean up the complete Objective-C messaging flow1 for myself and to keep a record for later reference.
NilTest: if receiver is nil, return nil.
CacheLookup: look up IMP in per-class dispatch cache table, use it if found.
MethodTableLookup & lookUpImpOrForward:
- Look up IMP in class hierarchy bottom-up, cache it and use it if found.
- Try Dynamic Method Resolution:
+resolveInstanceMethod:
and+resolveClassMethod:
. Step 3.1 will be tried again afterward. - Try Fast Message Forwarding — Selector Forwarding:
-forwardingTargetForSelector:
. - Try Slow Message Forwarding — Invocation Forwarding:
-methodSignatureForSelector:
and-forwardInvocation:
. - Finally, if nothing above helps,
-doesNotRecognizeSelector:
is called(by-[NSObject forwardInvocation:]
) andNSInvalidArgumentException
is raised.
Q:
- Does
-respondsToSelector:
use Message Forwarding? - Does
-respondsToSelector:
use Dynamic Method Resolution? - Why? And why Dynamic Method Resolution is tried before Message Forwarding?
- Why is
-methodSignatureForSelector:
required for Invocation Forwarding?
.
.
.
.
.
.
.
A:
- No.
- Yes.
- Dynamic Method Resolution adds real method IMP into dispatch table and thereafter it has no difference from statically implemented method at all to the runtime — it is one-off indirection and fallback. Message Forwarding is lifetime indirection and fallback.
- To pack and unpack arguments. Method signature is just type encoding wrapped in object. Invocation creating is message recording, which is a data archiving process. Invocation forwarding is message replay, which is a data unarchiving process. To unarchive the archived data, type information of the data is necessary.