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.

  1. NilTest: if receiver is nil, return nil.

  2. CacheLookup: look up IMP in per-class dispatch cache table, use it if found.

  3. MethodTableLookup & lookUpImpOrForward:

    1. Look up IMP in class hierarchy bottom-up, cache it and use it if found.
    2. Try Dynamic Method Resolution: +resolveInstanceMethod: and +resolveClassMethod:. Step 3.1 will be tried again afterward.
    3. Try Fast Message ForwardingSelector Forwarding: -forwardingTargetForSelector:.
    4. Try Slow Message ForwardingInvocation Forwarding: -methodSignatureForSelector: and -forwardInvocation:.
    5. Finally, if nothing above helps, -doesNotRecognizeSelector: is called(by -[NSObject forwardInvocation:]) and NSInvalidArgumentException is raised.

Q:

  1. Does -respondsToSelector: use Message Forwarding?
  2. Does -respondsToSelector: use Dynamic Method Resolution?
  3. Why? And why Dynamic Method Resolution is tried before Message Forwarding?
  4. Why is -methodSignatureForSelector: required for Invocation Forwarding?

.
.
.
.
.
.
.

A:

  1. No.
  2. Yes.
  3. 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.
  4. 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.

  1. For forwarding, here is a more complete and detailed article