How does forwardInvocation: get called?
Asked Answered
I

2

5

Looking only at the Objective-C runtime library, when a message is sent to an object that doesn't respond to it, the runtime system gives the receiver another chance to handle the message. So, the receiver's forward:: method, if implemented, gets called. However, looking at NSObject.mm, NSObject doesn't seem to implement forward::.

So, how does NSObject's forwardInvocation: method gets called, since the only thing the runtime system calls when a forwarding is needed is forward::? Does Foundation use objc_setForwardHandler (runtime.h) to set a new handler that calls forwardInvocation: whenever a message sent to a NSObject object needs to be forwarded?

Initiative answered 2/3, 2013 at 19:21 Comment(0)
S
12

At some point way back in time, there was no NSObject in the Objective-C runtime. When the language was first created by Brad Cox and Tom Love they added in a root object class, called Object. This implemented [Object forward::] , which was used to do message forwarding.

A few years later, NextStep came along and made their own additions to the language, creating the OpenStep framework (which became Cocoa). NextStep got rid of the Object class, and replaced it with NSObject. One of the changes that was made was to replace the forward:: method with forwardInvocation. The Object class is still kicking around in the source code (as you have found), but I'm pretty sure it's not available in either iOS or 64 bit OS X apps.

You are correct to suggest that objc_setForwardHandler is used to indicate that forwardInvocation should be used instead of forward:: for all NSObjects. I am afraid I'm not sure when Foundation calls this...I would guess at NSObject initialisation. I am also not massively up on the underlying runtime implementation, but hopefully that will have been of at least some help?

Solent answered 2/3, 2013 at 20:19 Comment(6)
According to an Apple mailing list post from about six years ago (link here) you can't use objc_setForwardHandler unless you're running without foundation. The thread I linked to might have more information that could help you.Solent
Yes, it helped me. Now I'm sure Foundation calls objc_setForwardHandler to make forwardInvocation get called. If I call objc_setForwardHandler(NULL, NULL), what would override any previously set forward handler, the forward:: method of my class is called, instead of forwardInvocation. So, most surely, on startup, Foundation calls objc_setForwardHandler passing forwardInvocation's IMP as arguments.Initiative
You would assume so. I know that the Cocotron open source implementation of Foundation does it on NSObject initialization (source here).Solent
Setting a breakpoint on objc_setForwardHandler shows that it is called from __CFInitialize in the CoreFoundation library.Ogee
"but I'm pretty sure it's not available in either iOS or 64 bit OS X apps" What do you mean "not available"?Twobit
@Twobit - it's not included in Foundation or the run-time. GCC also deprecated it and removed any useful methods from their implementation in 2011. If you try and use Object when targeting iOS or 64-bit OS X you'll get an error, and XCode will re-direct you to the NSObject documentation.Solent
F
1

This SO post has a more detailed answer to your question as to what happen when a message is sent to an object that doesn't respond to it.

Fortier answered 9/4, 2013 at 14:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.