forwardInvocation到其他类而不是实例

时间:2012-06-02 14:15:22

标签: objective-c

我有一个facade单例,我想将一些类方法调用转发给一些“静态”类。

乍一看,forwardInvocation:似乎是一种可能的解决方案,但NSInvocation的{​​{1}}和invokeWithTarget:只接受setTarget:,i。即指向实例的指针,而不是类本身。我尝试将id作为目标移交,但当我在某处调用[MyTargetClass class]时,我仍然会收到“没有已知的类方法[...]”错误。当我调用[Facade someForwardedMethod]时,我得到一个“No visible @interface [...]声明选择器[...]”错误。

当然我知道我还需要覆盖[[Facade sharedInstance] someForwardedMethod]respondsToSelector:,因此我的代码如下所示:

methodSignatureForSelector:

有没有办法让这项工作成功,还是我必须选择另一种方法?


编辑:Rob Napier在他的回答中提到了两种方式,这是我的发现:

我可以通过带有

的facade实例在我的目标类中调用一个类方法
- (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];
    }
}

这比我希望的有点丑,但它确实有效。但是,当我处理facade类时,我无法在目标类中调用类方法。为了使编译器安静,我可以编写

[(id)[Facade sharedInstance] doSomethingClassyInTargetClass];

然后它会在运行时抛出'NSInvalidArgumentException'“[Facade doSomethingClassyInTargetClass]:无法识别的选择器发送到类[...]”。显然,Facile类的类方法在不尊重[(Class)[Facade class] doSomethingClassyInTargetClass]; 的情况下得到解决,但毕竟前面有一个forwardInvocation: ......

1 个答案:

答案 0 :(得分:5)

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

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

[obj doSomething];

现在,MyObject实际上并未在其标题中声明doSomething,即使它会响应它。所以编译器抱怨这可能不起作用。解决方法是:

[(id)obj doSomething];

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

现在,对于课程,您无法使用id,但您应该可以使用Class来实现相同的目标,例如:

[(Class)MyClass doSomethingClassy];

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

你也应该看看Ken Thomases引用的forwardTargetForSelector:


您无需将sharedInstance投射到id。只需更改签名,因为您总是希望以这种方式使用它:

+ (id)sharedInstance;