forwardInvocation 到其他类而不是实例 [英] forwardInvocation to other class instead of instance

查看:88
本文介绍了forwardInvocation 到其他类而不是实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 facade 单例,我想将一些类方法调用转发给某些静态"类.

I have a facade singleton that I'd like to forward some class method calls to some "static" class.

乍一看,forwardInvocation: 似乎是一个可能的解决方案,但是,NSInvocationinvokeWithTarget:setTarget: 只接受一个 id, i.e.指向实例的指针,而不是类本身.我尝试将 [MyTargetClass class] 作为目标移交,但是当我调用 [Facade someForwardedMethod] 时仍然收到No known class method [...]"错误某处.当我调用 [[Facade sharedInstance] someForwardedMethod] 时,我收到没有可见的 @interface [...] 声明选择器 [...]"错误.

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.

当然我知道我还需要覆盖 respondsToSelector:methodSignatureForSelector:,所以我的代码看起来像这样:

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?

我已经尝试了 Rob Napier 在他的回答中提到的两种方式,以下是我的发现:

I have tried both ways that Rob Napier mentions in his answer, here are my findings:

我可以通过 Facade 实例调用目标类中的类方法

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];

但是它会在运行时抛出一个NSInvalidArgumentException"[Facade doSomethingClassyInTargetClass]: unrecognized selector sent to class [...]".显然,外观类的类方法在不考虑 forwardInvocation: 的情况下得到解决,但毕竟它前面有一个 -...

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...

推荐答案

啊,当你添加No visible @interface [...] 声明选择器 [...]"时,一切都清楚了.

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

>

考虑一个只有实例方法的更简单的形式.你实现了-forwardInvocation:,然后你有这样的代码:

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

[obj doSomething];

现在,MyObject 实际上并没有在其标头中声明 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];

当你声明一些id时,编译器停止检查目标是否实际实现了选择器.但也有可能no 接口声明了doSomething.然后编译器再次怀疑它可能是一个错字,并给你一个警告.无接口"是指没有编译器可以访问的接口".编译器只能访问此编译单元中的接口(即 .m 文件及其包含的头文件).因此,您需要确保包含定义此选择器的标头.

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.

现在对于类,你不能使用id,但是你应该可以使用Class来实现同样的事情,比如:

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];

如果可能想查看 RNObserverManager 示例来自 iOS:PTL 第 4 章的代码,演示了类似的内容.

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

您还应该查看 Ken Thomases 引用的 forwardTargetForSelector:.

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

您不必将 sharedInstance 转换为 id.只需更改签名,因为您总是希望以这种方式使用它:

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;

这篇关于forwardInvocation 到其他类而不是实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆