Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What determines the process by which unimplemented methods are resolved?

As I understand it, an unimplemented method gets resolved in the following way:

  1. resolveInstanceMethod: / resolveClassMethod: gets a chance to implement the method
  2. forwardingTargetForSelector: gets a chance to forward to a delegate
  3. forwardInvocation: gets a chance to handle the method as it sees fit.

Where is this three-step process defined? I'd like to handle it myself as NSInvocation might be too heavyweight for my needs. I've had a poke around the runtime source and can't really see anything.

It looks like the old runtime would call forward:args: on the receiver, to do this but that seems to have gone from the new one. I'm guessing that the process must be defined by the framework rather than the runtime, since it'd be strange if the runtime depended on Cocoa to the extent of requiring NSInvocation to handle messages. Is it maybe an undocumented method that gets called on NSObject / NSProxy?

Edit:

It looks like the runtime declares, but never defines, a C function which is called when objc_msgSend can't find an implementation:

id objc_msgForward(id object,SEL message,...);

I don't work for Apple, so I don't know how Foundation implements this, but at least in the case of Cocotron, they use:

id objc_msgForward(id object,SEL message,...)
{
   Class       class=object->isa;
   struct objc_method *method;
   void       *arguments=&object;

   if((method=class_getInstanceMethod(class,@selector(forwardSelector:arguments:)))!=NULL)
        return method->method_imp(object,@selector(forwardSelector:arguments:),message,arguments);
   else
   {
       OBJCRaiseException("OBJCDoesNotRecognizeSelector","%c[%s %s(%d)]", class_isMetaClass(class) ? '+' : '-', class->name,sel_getName(message),message);
       return nil;
   }
}

adding a forwardSelector:arguments: method doesn't seem to work, so I'm guessing this is specific to Cocotron. Anyone know what objc_msgForward does in Foundation?

like image 560
Chris Devereux Avatar asked Jan 29 '11 05:01

Chris Devereux


1 Answers

I'm writing something a bit like a scripting language that uses message forwarding to interface with objective-c. For now, I'm using NSInvocation, but it could end up doing this thousands of times per second, so the overhead would be noticeable. But I guess I'm also just curious...

As far as message forwarding is concerned, the behavior is [often subtly] different across different platforms and versions of the runtime.

In any case, don't re-invent the wheel. There are two language bridges available today that do pretty close to full-fidelity bridging from which you can learn a ton. Both have liberal licenses specifically to allow for such re-use.

Specifically, the MacRuby project offers a Ruby implementation that sits on top of CoreFoundation and the Objective-C Garbage Collector. It is the "most native" bridge available (and not terribly portable as a result -- not a goal of the project).

The PyObjC bridge is the best example available of a high fidelity bridge between the Objective-C runtime and another dynamic OO language's runtime; Python. It is a bit more portable, though the non-Mac OS X bits have likely rotted somewhat.

(I would be remiss in not mentioning F-Script; a new language built on Objective-C for which, I believe, the source is/was available?)

All of the bridges deal with both method forwarding, subclassing and cross-runtime proxying, all of which sound like they are applicable to your particular needs.

like image 98
bbum Avatar answered Oct 23 '22 05:10

bbum