Exploring the OC Message Sending Mechanism
This article provides an in‑depth analysis of Objective‑C's runtime message‑sending process, covering the roles of objc_msgSend, method caching, dynamic method resolution, and message forwarding, with detailed code examples and assembly snippets to illustrate each step.
The Objective‑C runtime implements message sending through a multi‑stage process that can be divided into three main parts: message dispatch, dynamic method resolution, and message forwarding. When objc_msgSend is invoked, the runtime first checks for a nil receiver, then looks up a cached IMP in the class’s cache list. If the cache misses, it searches the method list, traverses the inheritance chain, and finally falls back to dynamic resolution or forwarding.
Method caching optimizes repeated calls by storing selector‑IMP pairs in a hash‑based cache_t structure. The cache consists of bucket_t entries that map a SEL (key) to an IMP (function pointer). On the first invocation, the runtime populates the cache; subsequent calls retrieve the IMP directly, avoiding costly method‑list scans.
If a selector is not found, the runtime attempts dynamic method resolution via resolveInstanceMethod: or resolveClassMethod: . Developers can add an implementation at runtime using class_addMethod , providing a C function that receives the hidden self and _cmd parameters.
When resolution fails, the message is forwarded. The runtime first calls forwardingTargetForSelector: to redirect the message to another object. If that returns nil, it creates an NSMethodSignature in methodSignatureForSelector: and finally invokes forwardInvocation: , where an NSInvocation object can be manipulated or redirected to a different target. If all forwarding steps are unhandled, doesNotRecognizeSelector: raises an exception.
Practical applications include crash‑prevention by overriding resolveInstanceMethod: in a NSObject category to catch unimplemented selectors, and simulating multiple inheritance by forwarding selectors to delegate objects that implement different protocols.
void (*setter)(id, SEL, BOOL);
int i;
setter = (void (*)(id, SEL, BOOL))[target methodForSelector:@selector(setFilled:)];
for (i = 0; i < 1000; i++)
setter(targetList[i], @selector(setFilled:), YES); ENTRY _objc_msgSend
MESSENGER_START
NilTest
GetIsaFast
CacheLookup
LCacheMiss:
MethodTableLookup %a1, %a2
cmp %r11, %r11
jmp *%r11
END_ENTRY _objc_msgSendSohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.