forwardInvocation to other class instead of instance

objective-c

Solution

Ah, when you added the "No visible @interface [...] declares the selector [...]", it is all clear.

Consider a simpler form with just instance methods. You implement `-forwardInvocation:`, and then you have code like this:

[obj doSomething];

Now, `MyObject` doesn't actually claim `doSomething` in its header, even though it will respond to it. So the compiler complains that this probably won't work. The fix for that is:

[(id)obj doSomething];

When you declare something `id`, the compiler stops checking whether the target actually implements the selector. But it's also possible that no interface declares `doSomething`. Then the compiler is once again suspicious that it's probably a typo, and gives you a warning. And by "no interface," I mean "no interface that the compiler has access to." The compiler only has access to interfaces in this compile unit (i.e. the .m file and the headers it includes). So you need to make sure you include the header that defines this selector.

Now for classes, you can't use `id`, but you should be able to use `Class` to achieve the same thing, such as:

[(Class)MyClass doSomethingClassy];

If may want to see the RNObserverManager sample code from iOS:PTL Chapter 4 which demonstrates something similar.

You should also definitely look at `forwardTargetForSelector:` that Ken Thomases references.

You don't have to cast `sharedInstance` to `id`. Just change the signature, since you'll always want to use it that way:

+ (id)sharedInstance;

Problem

I have a facade singleton that I'd like to forward some class method calls to some "static" class. At first glance, `forwardInvocation:` appeared to be a possible solution, however, `NSInvocation`'s `invokeWithTarget:` and `setTarget:` only accept an `id`, i. e. a pointer to an instance, not a class itself. I tried handing over `[MyTargetClass class]` as the target, but I still get a "No known class method [...]" error when I call `[Facade someForwardedMethod]` somewhere. When I call `[[Facade sharedInstance] someForwardedMethod]` I get a "No visible @interface [...] declares the selector [...]" error. Of course I am aware that I also need to override `respondsToSelector:` and `methodSignatureForSelector:`, so my code looks like this: ``` - (BOOL)respondsToSelector:(SEL)aSelector { if ([super respondsToSelector:aSelector]) { return YES; } else { return [MyTargetClass respondsToSelector:aSelector]; } } - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { NSMethodSignature* signature = [super methodSignatureForSelector:selector]; if (!signature) { signature = [MyTargetClass methodSignatureForSelector:selector]; } return signature; } - (void)forwardInvocation:(NSInvocation *)anInvocation { SEL aSelector = [anInvocation selector]; if ([MyTargetClass respondsToSelector: aSelector]) { [anInvocation invokeWithTarget:[MyTargetClass class]]; } else { [super forwardInvocation:anInvocation]; } } ``` Is there a way to make this work, or do I have to choose another approach? EDIT: I have tried both ways that Rob Napier mentions in his answer, here are my findings: I can call a class method in my target class through the facade instance with ``` [(id)[Facade sharedInstance] doSomethingClassyInTargetClass]; ``` It's a bit uglier than I hoped for, but it works. However, I can not call a class method in my target class when I address the facade class. To quieten the compiler I can write ``` [(Class)[Facade class] doSomethingClassyInTargetClass]; ``` but then it throws an 'NSInvalidArgumentException' "[Facade doSomethingClassyInTargetClass]: unrecognized selector sent to class [...]" at runtime. Apparently the class methods of the facade class get resolved without respect for `forwardInvocation:`, but after all it has a `-` in front...

Original source

Related problems